[INFO] cloning repository https://github.com/hydro-project/HydraulicLift
[INFO] running `Command { std: "git" "-c" "credential.helper=" "-c" "credential.helper=/workspace/cargo-home/bin/git-credential-null" "clone" "--bare" "https://github.com/hydro-project/HydraulicLift" "/workspace/cache/git-repos/https%3A%2F%2Fgithub.com%2Fhydro-project%2FHydraulicLift", kill_on_drop: false }`
[INFO] [stderr] Cloning into bare repository '/workspace/cache/git-repos/https%3A%2F%2Fgithub.com%2Fhydro-project%2FHydraulicLift'...
[INFO] running `Command { std: "git" "rev-parse" "HEAD", kill_on_drop: false }`
[INFO] [stdout] 263ab26e539acc46107d6e03d075ab6a6910ef8b
[INFO] checking hydro-project/HydraulicLift against 3154cc1a3e6424e44f438a95007d043ed5ceaaf6+rustflags=-Znext-solver=coherence for pr-133502-30
[INFO] running `Command { std: "git" "clone" "/workspace/cache/git-repos/https%3A%2F%2Fgithub.com%2Fhydro-project%2FHydraulicLift" "/workspace/builds/worker-6-tc1/source", kill_on_drop: false }`
[INFO] [stderr] Cloning into '/workspace/builds/worker-6-tc1/source'...
[INFO] [stderr] done.
[INFO] started tweaking git repo https://github.com/hydro-project/HydraulicLift
[INFO] finished tweaking git repo https://github.com/hydro-project/HydraulicLift
[INFO] tweaked toml for git repo https://github.com/hydro-project/HydraulicLift written to /workspace/builds/worker-6-tc1/source/Cargo.toml
[INFO] validating manifest of git repo https://github.com/hydro-project/HydraulicLift on toolchain 3154cc1a3e6424e44f438a95007d043ed5ceaaf6
[INFO] running `Command { std: CARGO_HOME="/workspace/cargo-home" RUSTUP_HOME="/workspace/rustup-home" "/workspace/cargo-home/bin/cargo" "+3154cc1a3e6424e44f438a95007d043ed5ceaaf6" "metadata" "--manifest-path" "Cargo.toml" "--no-deps", kill_on_drop: false }`
[INFO] crate git repo https://github.com/hydro-project/HydraulicLift already has a lockfile, it will not be regenerated
[INFO] running `Command { std: CARGO_HOME="/workspace/cargo-home" RUSTUP_HOME="/workspace/rustup-home" "/workspace/cargo-home/bin/cargo" "+3154cc1a3e6424e44f438a95007d043ed5ceaaf6" "fetch" "--manifest-path" "Cargo.toml", kill_on_drop: false }`
[INFO] [stderr]     Blocking waiting for file lock on package cache
[INFO] [stderr]     Updating crates.io index
[INFO] [stderr]     Blocking waiting for file lock on package cache
[INFO] [stderr]  Downloading crates ...
[INFO] [stderr]   Downloaded stageleft_tool v0.3.0
[INFO] [stderr]   Downloaded syn-inline-mod v0.6.0
[INFO] [stderr]   Downloaded hydroflow_plus v0.9.0
[INFO] [stderr]   Downloaded stageleft v0.4.0
[INFO] [stderr]   Downloaded stageleft_macro v0.3.0
[INFO] [stderr]   Downloaded insta v1.40.0
[INFO] [stderr]   Downloaded clap v4.5.20
[INFO] [stderr]   Downloaded wasm-bindgen-shared v0.2.94
[INFO] [stderr]   Downloaded variadics v0.0.6
[INFO] [stderr]   Downloaded wasm-bindgen-macro v0.2.94
[INFO] [stderr]   Downloaded indexmap v2.6.0
[INFO] [stderr]   Downloaded syn v2.0.74
[INFO] [stderr]   Downloaded sealed v0.5.0
[INFO] [stderr]   Downloaded wasm-bindgen-macro-support v0.2.94
[INFO] [stderr]   Downloaded wasm-bindgen-backend v0.2.94
[INFO] [stderr]   Downloaded wasm-bindgen v0.2.94
[INFO] [stderr]   Downloaded js-sys v0.3.71
[INFO] [stderr]   Downloaded serde_json v1.0.128
[INFO] [stderr]   Downloaded hydroflow_lang v0.9.0
[INFO] [stderr]   Downloaded clap_builder v4.5.20
[INFO] [stderr]   Downloaded pusherator v0.0.8
[INFO] [stderr]   Downloaded cc-traits v2.0.0
[INFO] [stderr]   Downloaded libc v0.2.159
[INFO] [stderr]   Downloaded hydroflow v0.9.0
[INFO] [stderr]   Downloaded lattices_macro v0.5.6
[INFO] [stderr]   Downloaded lattices v0.5.7
[INFO] running `Command { std: "docker" "create" "-v" "/var/lib/crater-agent-workspace/builds/worker-6-tc1/source:/opt/rustwide/workdir:ro,Z" "-v" "/var/lib/crater-agent-workspace/builds/worker-6-tc1/target:/opt/rustwide/target:rw,Z" "-v" "/var/lib/crater-agent-workspace/cargo-home:/opt/rustwide/cargo-home:ro,Z" "-v" "/var/lib/crater-agent-workspace/rustup-home:/opt/rustwide/rustup-home:ro,Z" "-m" "1610612736" "--network" "none" "ghcr.io/rust-lang/crates-build-env/linux@sha256:77db811e55d90add9212f6832c23229e3de5f1c1f9905e8cb07319ea15df73ac" "sleep" "infinity", kill_on_drop: false }`
[INFO] [stdout] f851943bf4b86be4589959fc0027f4e68257cbfe85f1dfb26d1c109bae8353e5
[INFO] running `Command { std: "docker" "start" "f851943bf4b86be4589959fc0027f4e68257cbfe85f1dfb26d1c109bae8353e5", kill_on_drop: false }`
[INFO] running `Command { std: "docker" "inspect" "f851943bf4b86be4589959fc0027f4e68257cbfe85f1dfb26d1c109bae8353e5", kill_on_drop: false }`
[INFO] running `Command { std: "docker" "exec" "-e" "SOURCE_DIR=/opt/rustwide/workdir" "-e" "CARGO_HOME=/opt/rustwide/cargo-home" "-e" "RUSTUP_HOME=/opt/rustwide/rustup-home" "-e" "CARGO_TARGET_DIR=/opt/rustwide/target" "-w" "/opt/rustwide/workdir" "--user" "0:0" "f851943bf4b86be4589959fc0027f4e68257cbfe85f1dfb26d1c109bae8353e5" "/opt/rustwide/cargo-home/bin/cargo" "+3154cc1a3e6424e44f438a95007d043ed5ceaaf6" "metadata" "--no-deps" "--format-version=1", kill_on_drop: false }`
[INFO] running `Command { std: "docker" "inspect" "f851943bf4b86be4589959fc0027f4e68257cbfe85f1dfb26d1c109bae8353e5", kill_on_drop: false }`
[INFO] running `Command { std: "docker" "exec" "-e" "SOURCE_DIR=/opt/rustwide/workdir" "-e" "CARGO_HOME=/opt/rustwide/cargo-home" "-e" "RUSTUP_HOME=/opt/rustwide/rustup-home" "-e" "CARGO_TARGET_DIR=/opt/rustwide/target" "-e" "CARGO_INCREMENTAL=0" "-e" "RUST_BACKTRACE=full" "-e" "RUSTFLAGS=--cap-lints=forbid -Znext-solver=coherence" "-e" "RUSTDOCFLAGS=--cap-lints=forbid" "-w" "/opt/rustwide/workdir" "--user" "0:0" "f851943bf4b86be4589959fc0027f4e68257cbfe85f1dfb26d1c109bae8353e5" "/opt/rustwide/cargo-home/bin/cargo" "+3154cc1a3e6424e44f438a95007d043ed5ceaaf6" "check" "--frozen" "--all" "--all-targets" "--message-format=json", kill_on_drop: false }`
[INFO] [stderr]    Compiling proc-macro2 v1.0.86
[INFO] [stderr]    Compiling libc v0.2.159
[INFO] [stderr]    Compiling serde v1.0.210
[INFO] [stderr]    Compiling hashbrown v0.15.0
[INFO] [stderr]    Compiling pin-project-lite v0.2.14
[INFO] [stderr]    Compiling toml_datetime v0.6.8
[INFO] [stderr]     Checking unicode-ident v1.0.12
[INFO] [stderr]    Compiling typenum v1.17.0
[INFO] [stderr]    Compiling bytes v1.7.2
[INFO] [stderr]    Compiling cpufeatures v0.2.14
[INFO] [stderr]     Checking smallvec v1.13.2
[INFO] [stderr]     Checking anstyle-parse v0.2.5
[INFO] [stderr]     Checking anstyle v1.0.8
[INFO] [stderr]    Compiling prettyplease v0.2.20
[INFO] [stderr]     Checking anstyle-query v1.1.1
[INFO] [stderr]     Checking colorchoice v1.0.2
[INFO] [stderr]     Checking futures-channel v0.3.31
[INFO] [stderr]    Compiling slotmap v1.0.7
[INFO] [stderr]     Checking either v1.13.0
[INFO] [stderr]    Compiling serde_json v1.0.128
[INFO] [stderr]     Checking clap_lex v0.7.2
[INFO] [stderr]    Compiling ref-cast v1.0.23
[INFO] [stderr]     Checking winnow v0.5.40
[INFO] [stderr]     Checking anstream v0.6.15
[INFO] [stderr]     Checking regex-automata v0.4.8
[INFO] [stderr]     Checking tracing-core v0.1.32
[INFO] [stderr]     Checking cc-traits v2.0.0
[INFO] [stderr]     Checking itertools v0.10.5
[INFO] [stderr]     Checking similar v2.6.0
[INFO] [stderr]     Checking by_address v1.2.1
[INFO] [stderr]     Checking clap_builder v4.5.20
[INFO] [stderr]    Compiling tokio v1.40.0
[INFO] [stderr]    Compiling indexmap v2.6.0
[INFO] [stderr]    Compiling generic-array v0.14.7
[INFO] [stderr]     Checking quote v1.0.36
[INFO] [stderr]     Checking syn v2.0.74
[INFO] [stderr]     Checking parking_lot_core v0.9.10
[INFO] [stderr]     Checking signal-hook-registry v1.4.2
[INFO] [stderr]     Checking mio v1.0.2
[INFO] [stderr]     Checking socket2 v0.5.7
[INFO] [stderr]     Checking console v0.15.8
[INFO] [stderr]     Checking parking_lot v0.12.3
[INFO] [stderr]    Compiling block-buffer v0.10.4
[INFO] [stderr]    Compiling crypto-common v0.1.6
[INFO] [stderr]    Compiling digest v0.10.7
[INFO] [stderr]    Compiling toml_edit v0.19.15
[INFO] [stderr]    Compiling sha2 v0.10.8
[INFO] [stderr]     Checking regex v1.11.0
[INFO] [stderr]     Checking proc-macro-crate v1.3.1
[INFO] [stderr]    Compiling syn-inline-mod v0.6.0
[INFO] [stderr]    Compiling serde_derive v1.0.210
[INFO] [stderr]    Compiling async-trait v0.1.83
[INFO] [stderr]    Compiling tokio-macros v2.4.0
[INFO] [stderr]    Compiling sealed v0.5.0
[INFO] [stderr]    Compiling futures-macro v0.3.31
[INFO] [stderr]    Compiling hydroflow_lang v0.9.0
[INFO] [stderr]    Compiling clap_derive v4.5.18
[INFO] [stderr]    Compiling tracing-attributes v0.1.27
[INFO] [stderr]    Compiling lattices_macro v0.5.6
[INFO] [stderr]    Compiling ref-cast-impl v1.0.23
[INFO] [stderr]    Compiling auto_impl v1.2.0
[INFO] [stderr]     Checking variadics v0.0.6
[INFO] [stderr]     Checking pusherator v0.0.8
[INFO] [stderr]    Compiling sha256 v1.5.0
[INFO] [stderr]    Compiling stageleft_tool v0.3.0
[INFO] [stderr]    Compiling stageleft_macro v0.3.0
[INFO] [stderr]     Checking futures-util v0.3.31
[INFO] [stderr]     Checking tracing v0.1.40
[INFO] [stderr]    Compiling hydroflow_plus v0.9.0
[INFO] [stderr]     Checking stageleft v0.4.0
[INFO] [stderr]     Checking clap v4.5.20
[INFO] [stderr]     Checking futures-executor v0.3.31
[INFO] [stderr]     Checking futures v0.3.31
[INFO] [stderr]     Checking tokio-util v0.7.12
[INFO] [stderr]     Checking lattices v0.5.7
[INFO] [stderr]     Checking bincode v1.3.3
[INFO] [stderr]     Checking insta v1.40.0
[INFO] [stderr]     Checking tokio-stream v0.1.16
[INFO] [stderr]     Checking hydroflow v0.9.0
[INFO] [stdout] error[E0557]: feature has been removed
[INFO] [stdout]  --> /opt/rustwide/cargo-home/registry/src/index.crates.io-1949cf8c6b5b557f/hydroflow_plus-0.9.0/src/lib.rs:1:12
[INFO] [stdout]   |
[INFO] [stdout] 1 | #![feature(box_patterns)]
[INFO] [stdout]   |            ^^^^^^^^^^^^ feature has been removed
[INFO] [stdout]   |
[INFO] [stdout]   = note: removed in 1.100.0
[INFO] [stdout]   = note: superseded by `deref_patterns`
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] error: `box` patterns have been removed (feature `box_patterns`)
[INFO] [stdout]   --> /opt/rustwide/cargo-home/registry/src/index.crates.io-1949cf8c6b5b557f/hydroflow_plus-0.9.0/src/persist_pullup.rs:18:31
[INFO] [stdout]    |
[INFO] [stdout] 18 |         HfPlusNode::Unpersist(box HfPlusNode::Persist(_)) => {
[INFO] [stdout]    |                               ^^^
[INFO] [stdout]    |
[INFO] [stdout]    = help: enable feature `deref_patterns` instead and...
[INFO] [stdout] help: ...if possible just remove keyword `box`...
[INFO] [stdout]    |
[INFO] [stdout] 18 -         HfPlusNode::Unpersist(box HfPlusNode::Persist(_)) => {
[INFO] [stdout] 18 +         HfPlusNode::Unpersist(HfPlusNode::Persist(_)) => {
[INFO] [stdout]    |
[INFO] [stdout] help: ...otherwise replace it with an invocation of macro `deref`
[INFO] [stdout]    |
[INFO] [stdout] 18 -         HfPlusNode::Unpersist(box HfPlusNode::Persist(_)) => {
[INFO] [stdout] 18 +         HfPlusNode::Unpersist(deref!(HfPlusNode::Persist(_))) => {
[INFO] [stdout]    |
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] error: `box` patterns have been removed (feature `box_patterns`)
[INFO] [stdout]   --> /opt/rustwide/cargo-home/registry/src/index.crates.io-1949cf8c6b5b557f/hydroflow_plus-0.9.0/src/persist_pullup.rs:19:66
[INFO] [stdout]    |
[INFO] [stdout] 19 |             if let HfPlusNode::Unpersist(box HfPlusNode::Persist(box behind_persist)) =
[INFO] [stdout]    |                                                                  ^^^
[INFO] [stdout]    |
[INFO] [stdout]    = help: enable feature `deref_patterns` instead and...
[INFO] [stdout] help: ...if possible just remove keyword `box`...
[INFO] [stdout]    |
[INFO] [stdout] 19 -             if let HfPlusNode::Unpersist(box HfPlusNode::Persist(box behind_persist)) =
[INFO] [stdout] 19 +             if let HfPlusNode::Unpersist(box HfPlusNode::Persist(behind_persist)) =
[INFO] [stdout]    |
[INFO] [stdout] help: ...otherwise replace it with an invocation of macro `deref`
[INFO] [stdout]    |
[INFO] [stdout] 19 -             if let HfPlusNode::Unpersist(box HfPlusNode::Persist(box behind_persist)) =
[INFO] [stdout] 19 +             if let HfPlusNode::Unpersist(box HfPlusNode::Persist(deref!(behind_persist))) =
[INFO] [stdout]    |
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] error: `box` patterns have been removed (feature `box_patterns`)
[INFO] [stdout]   --> /opt/rustwide/cargo-home/registry/src/index.crates.io-1949cf8c6b5b557f/hydroflow_plus-0.9.0/src/persist_pullup.rs:19:42
[INFO] [stdout]    |
[INFO] [stdout] 19 |             if let HfPlusNode::Unpersist(box HfPlusNode::Persist(box behind_persist)) =
[INFO] [stdout]    |                                          ^^^
[INFO] [stdout]    |
[INFO] [stdout]    = help: enable feature `deref_patterns` instead and...
[INFO] [stdout] help: ...if possible just remove keyword `box`...
[INFO] [stdout]    |
[INFO] [stdout] 19 -             if let HfPlusNode::Unpersist(box HfPlusNode::Persist(box behind_persist)) =
[INFO] [stdout] 19 +             if let HfPlusNode::Unpersist(HfPlusNode::Persist(box behind_persist)) =
[INFO] [stdout]    |
[INFO] [stdout] help: ...otherwise replace it with an invocation of macro `deref`
[INFO] [stdout]    |
[INFO] [stdout] 19 -             if let HfPlusNode::Unpersist(box HfPlusNode::Persist(box behind_persist)) =
[INFO] [stdout] 19 +             if let HfPlusNode::Unpersist(deref!(HfPlusNode::Persist(box behind_persist))) =
[INFO] [stdout]    |
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] error: `box` patterns have been removed (feature `box_patterns`)
[INFO] [stdout]   --> /opt/rustwide/cargo-home/registry/src/index.crates.io-1949cf8c6b5b557f/hydroflow_plus-0.9.0/src/persist_pullup.rs:28:27
[INFO] [stdout]    |
[INFO] [stdout] 28 |         HfPlusNode::Delta(box HfPlusNode::Persist(_)) => {
[INFO] [stdout]    |                           ^^^
[INFO] [stdout]    |
[INFO] [stdout]    = help: enable feature `deref_patterns` instead and...
[INFO] [stdout] help: ...if possible just remove keyword `box`...
[INFO] [stdout]    |
[INFO] [stdout] 28 -         HfPlusNode::Delta(box HfPlusNode::Persist(_)) => {
[INFO] [stdout] 28 +         HfPlusNode::Delta(HfPlusNode::Persist(_)) => {
[INFO] [stdout]    |
[INFO] [stdout] help: ...otherwise replace it with an invocation of macro `deref`
[INFO] [stdout]    |
[INFO] [stdout] 28 -         HfPlusNode::Delta(box HfPlusNode::Persist(_)) => {
[INFO] [stdout] 28 +         HfPlusNode::Delta(deref!(HfPlusNode::Persist(_))) => {
[INFO] [stdout]    |
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] error: `box` patterns have been removed (feature `box_patterns`)
[INFO] [stdout]   --> /opt/rustwide/cargo-home/registry/src/index.crates.io-1949cf8c6b5b557f/hydroflow_plus-0.9.0/src/persist_pullup.rs:29:62
[INFO] [stdout]    |
[INFO] [stdout] 29 |             if let HfPlusNode::Delta(box HfPlusNode::Persist(box behind_persist)) =
[INFO] [stdout]    |                                                              ^^^
[INFO] [stdout]    |
[INFO] [stdout]    = help: enable feature `deref_patterns` instead and...
[INFO] [stdout] help: ...if possible just remove keyword `box`...
[INFO] [stdout]    |
[INFO] [stdout] 29 -             if let HfPlusNode::Delta(box HfPlusNode::Persist(box behind_persist)) =
[INFO] [stdout] 29 +             if let HfPlusNode::Delta(box HfPlusNode::Persist(behind_persist)) =
[INFO] [stdout]    |
[INFO] [stdout] help: ...otherwise replace it with an invocation of macro `deref`
[INFO] [stdout]    |
[INFO] [stdout] 29 -             if let HfPlusNode::Delta(box HfPlusNode::Persist(box behind_persist)) =
[INFO] [stdout] 29 +             if let HfPlusNode::Delta(box HfPlusNode::Persist(deref!(behind_persist))) =
[INFO] [stdout]    |
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] error: `box` patterns have been removed (feature `box_patterns`)
[INFO] [stdout]   --> /opt/rustwide/cargo-home/registry/src/index.crates.io-1949cf8c6b5b557f/hydroflow_plus-0.9.0/src/persist_pullup.rs:29:38
[INFO] [stdout]    |
[INFO] [stdout] 29 |             if let HfPlusNode::Delta(box HfPlusNode::Persist(box behind_persist)) =
[INFO] [stdout]    |                                      ^^^
[INFO] [stdout]    |
[INFO] [stdout]    = help: enable feature `deref_patterns` instead and...
[INFO] [stdout] help: ...if possible just remove keyword `box`...
[INFO] [stdout]    |
[INFO] [stdout] 29 -             if let HfPlusNode::Delta(box HfPlusNode::Persist(box behind_persist)) =
[INFO] [stdout] 29 +             if let HfPlusNode::Delta(HfPlusNode::Persist(box behind_persist)) =
[INFO] [stdout]    |
[INFO] [stdout] help: ...otherwise replace it with an invocation of macro `deref`
[INFO] [stdout]    |
[INFO] [stdout] 29 -             if let HfPlusNode::Delta(box HfPlusNode::Persist(box behind_persist)) =
[INFO] [stdout] 29 +             if let HfPlusNode::Delta(deref!(HfPlusNode::Persist(box behind_persist))) =
[INFO] [stdout]    |
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] error: `box` patterns have been removed (feature `box_patterns`)
[INFO] [stdout]   --> /opt/rustwide/cargo-home/registry/src/index.crates.io-1949cf8c6b5b557f/hydroflow_plus-0.9.0/src/persist_pullup.rs:48:48
[INFO] [stdout]    |
[INFO] [stdout] 48 |                     if let HfPlusNode::Persist(box behind_persist) =
[INFO] [stdout]    |                                                ^^^
[INFO] [stdout]    |
[INFO] [stdout]    = help: enable feature `deref_patterns` instead and...
[INFO] [stdout] help: ...if possible just remove keyword `box`...
[INFO] [stdout]    |
[INFO] [stdout] 48 -                     if let HfPlusNode::Persist(box behind_persist) =
[INFO] [stdout] 48 +                     if let HfPlusNode::Persist(behind_persist) =
[INFO] [stdout]    |
[INFO] [stdout] help: ...otherwise replace it with an invocation of macro `deref`
[INFO] [stdout]    |
[INFO] [stdout] 48 -                     if let HfPlusNode::Persist(box behind_persist) =
[INFO] [stdout] 48 +                     if let HfPlusNode::Persist(deref!(behind_persist)) =
[INFO] [stdout]    |
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] error: `box` patterns have been removed (feature `box_patterns`)
[INFO] [stdout]   --> /opt/rustwide/cargo-home/registry/src/index.crates.io-1949cf8c6b5b557f/hydroflow_plus-0.9.0/src/persist_pullup.rs:65:20
[INFO] [stdout]    |
[INFO] [stdout] 65 |             input: box HfPlusNode::Persist(_),
[INFO] [stdout]    |                    ^^^
[INFO] [stdout]    |
[INFO] [stdout]    = help: enable feature `deref_patterns` instead and...
[INFO] [stdout] help: ...if possible just remove keyword `box`...
[INFO] [stdout]    |
[INFO] [stdout] 65 -             input: box HfPlusNode::Persist(_),
[INFO] [stdout] 65 +             input: HfPlusNode::Persist(_),
[INFO] [stdout]    |
[INFO] [stdout] help: ...otherwise replace it with an invocation of macro `deref`
[INFO] [stdout]    |
[INFO] [stdout] 65 -             input: box HfPlusNode::Persist(_),
[INFO] [stdout] 65 +             input: deref!(HfPlusNode::Persist(_)),
[INFO] [stdout]    |
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] error: `box` patterns have been removed (feature `box_patterns`)
[INFO] [stdout]   --> /opt/rustwide/cargo-home/registry/src/index.crates.io-1949cf8c6b5b557f/hydroflow_plus-0.9.0/src/persist_pullup.rs:69:24
[INFO] [stdout]    |
[INFO] [stdout] 69 |                 input: box HfPlusNode::Persist(behind_persist),
[INFO] [stdout]    |                        ^^^
[INFO] [stdout]    |
[INFO] [stdout]    = help: enable feature `deref_patterns` instead and...
[INFO] [stdout] help: ...if possible just remove keyword `box`...
[INFO] [stdout]    |
[INFO] [stdout] 69 -                 input: box HfPlusNode::Persist(behind_persist),
[INFO] [stdout] 69 +                 input: HfPlusNode::Persist(behind_persist),
[INFO] [stdout]    |
[INFO] [stdout] help: ...otherwise replace it with an invocation of macro `deref`
[INFO] [stdout]    |
[INFO] [stdout] 69 -                 input: box HfPlusNode::Persist(behind_persist),
[INFO] [stdout] 69 +                 input: deref!(HfPlusNode::Persist(behind_persist)),
[INFO] [stdout]    |
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] error: `box` patterns have been removed (feature `box_patterns`)
[INFO] [stdout]   --> /opt/rustwide/cargo-home/registry/src/index.crates.io-1949cf8c6b5b557f/hydroflow_plus-0.9.0/src/persist_pullup.rs:83:20
[INFO] [stdout]    |
[INFO] [stdout] 83 |             input: box HfPlusNode::Persist(_),
[INFO] [stdout]    |                    ^^^
[INFO] [stdout]    |
[INFO] [stdout]    = help: enable feature `deref_patterns` instead and...
[INFO] [stdout] help: ...if possible just remove keyword `box`...
[INFO] [stdout]    |
[INFO] [stdout] 83 -             input: box HfPlusNode::Persist(_),
[INFO] [stdout] 83 +             input: HfPlusNode::Persist(_),
[INFO] [stdout]    |
[INFO] [stdout] help: ...otherwise replace it with an invocation of macro `deref`
[INFO] [stdout]    |
[INFO] [stdout] 83 -             input: box HfPlusNode::Persist(_),
[INFO] [stdout] 83 +             input: deref!(HfPlusNode::Persist(_)),
[INFO] [stdout]    |
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] error: `box` patterns have been removed (feature `box_patterns`)
[INFO] [stdout]   --> /opt/rustwide/cargo-home/registry/src/index.crates.io-1949cf8c6b5b557f/hydroflow_plus-0.9.0/src/persist_pullup.rs:87:24
[INFO] [stdout]    |
[INFO] [stdout] 87 |                 input: box HfPlusNode::Persist(behind_persist),
[INFO] [stdout]    |                        ^^^
[INFO] [stdout]    |
[INFO] [stdout]    = help: enable feature `deref_patterns` instead and...
[INFO] [stdout] help: ...if possible just remove keyword `box`...
[INFO] [stdout]    |
[INFO] [stdout] 87 -                 input: box HfPlusNode::Persist(behind_persist),
[INFO] [stdout] 87 +                 input: HfPlusNode::Persist(behind_persist),
[INFO] [stdout]    |
[INFO] [stdout] help: ...otherwise replace it with an invocation of macro `deref`
[INFO] [stdout]    |
[INFO] [stdout] 87 -                 input: box HfPlusNode::Persist(behind_persist),
[INFO] [stdout] 87 +                 input: deref!(HfPlusNode::Persist(behind_persist)),
[INFO] [stdout]    |
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] error: `box` patterns have been removed (feature `box_patterns`)
[INFO] [stdout]    --> /opt/rustwide/cargo-home/registry/src/index.crates.io-1949cf8c6b5b557f/hydroflow_plus-0.9.0/src/persist_pullup.rs:101:20
[INFO] [stdout]     |
[INFO] [stdout] 101 |             input: box HfPlusNode::Persist(_),
[INFO] [stdout]     |                    ^^^
[INFO] [stdout]     |
[INFO] [stdout]     = help: enable feature `deref_patterns` instead and...
[INFO] [stdout] help: ...if possible just remove keyword `box`...
[INFO] [stdout]     |
[INFO] [stdout] 101 -             input: box HfPlusNode::Persist(_),
[INFO] [stdout] 101 +             input: HfPlusNode::Persist(_),
[INFO] [stdout]     |
[INFO] [stdout] help: ...otherwise replace it with an invocation of macro `deref`
[INFO] [stdout]     |
[INFO] [stdout] 101 -             input: box HfPlusNode::Persist(_),
[INFO] [stdout] 101 +             input: deref!(HfPlusNode::Persist(_)),
[INFO] [stdout]     |
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] error: `box` patterns have been removed (feature `box_patterns`)
[INFO] [stdout]    --> /opt/rustwide/cargo-home/registry/src/index.crates.io-1949cf8c6b5b557f/hydroflow_plus-0.9.0/src/persist_pullup.rs:105:24
[INFO] [stdout]     |
[INFO] [stdout] 105 |                 input: box HfPlusNode::Persist(behind_persist),
[INFO] [stdout]     |                        ^^^
[INFO] [stdout]     |
[INFO] [stdout]     = help: enable feature `deref_patterns` instead and...
[INFO] [stdout] help: ...if possible just remove keyword `box`...
[INFO] [stdout]     |
[INFO] [stdout] 105 -                 input: box HfPlusNode::Persist(behind_persist),
[INFO] [stdout] 105 +                 input: HfPlusNode::Persist(behind_persist),
[INFO] [stdout]     |
[INFO] [stdout] help: ...otherwise replace it with an invocation of macro `deref`
[INFO] [stdout]     |
[INFO] [stdout] 105 -                 input: box HfPlusNode::Persist(behind_persist),
[INFO] [stdout] 105 +                 input: deref!(HfPlusNode::Persist(behind_persist)),
[INFO] [stdout]     |
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] error: `box` patterns have been removed (feature `box_patterns`)
[INFO] [stdout]    --> /opt/rustwide/cargo-home/registry/src/index.crates.io-1949cf8c6b5b557f/hydroflow_plus-0.9.0/src/persist_pullup.rs:118:20
[INFO] [stdout]     |
[INFO] [stdout] 118 |             input: box HfPlusNode::Persist(_),
[INFO] [stdout]     |                    ^^^
[INFO] [stdout]     |
[INFO] [stdout]     = help: enable feature `deref_patterns` instead and...
[INFO] [stdout] help: ...if possible just remove keyword `box`...
[INFO] [stdout]     |
[INFO] [stdout] 118 -             input: box HfPlusNode::Persist(_),
[INFO] [stdout] 118 +             input: HfPlusNode::Persist(_),
[INFO] [stdout]     |
[INFO] [stdout] help: ...otherwise replace it with an invocation of macro `deref`
[INFO] [stdout]     |
[INFO] [stdout] 118 -             input: box HfPlusNode::Persist(_),
[INFO] [stdout] 118 +             input: deref!(HfPlusNode::Persist(_)),
[INFO] [stdout]     |
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] error: `box` patterns have been removed (feature `box_patterns`)
[INFO] [stdout]    --> /opt/rustwide/cargo-home/registry/src/index.crates.io-1949cf8c6b5b557f/hydroflow_plus-0.9.0/src/persist_pullup.rs:127:24
[INFO] [stdout]     |
[INFO] [stdout] 127 |                 input: box HfPlusNode::Persist(behind_persist),
[INFO] [stdout]     |                        ^^^
[INFO] [stdout]     |
[INFO] [stdout]     = help: enable feature `deref_patterns` instead and...
[INFO] [stdout] help: ...if possible just remove keyword `box`...
[INFO] [stdout]     |
[INFO] [stdout] 127 -                 input: box HfPlusNode::Persist(behind_persist),
[INFO] [stdout] 127 +                 input: HfPlusNode::Persist(behind_persist),
[INFO] [stdout]     |
[INFO] [stdout] help: ...otherwise replace it with an invocation of macro `deref`
[INFO] [stdout]     |
[INFO] [stdout] 127 -                 input: box HfPlusNode::Persist(behind_persist),
[INFO] [stdout] 127 +                 input: deref!(HfPlusNode::Persist(behind_persist)),
[INFO] [stdout]     |
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] error: `box` patterns have been removed (feature `box_patterns`)
[INFO] [stdout]    --> /opt/rustwide/cargo-home/registry/src/index.crates.io-1949cf8c6b5b557f/hydroflow_plus-0.9.0/src/persist_pullup.rs:143:27
[INFO] [stdout]     |
[INFO] [stdout] 143 |         HfPlusNode::Union(box HfPlusNode::Persist(_), box HfPlusNode::Persist(_)) => {
[INFO] [stdout]     |                           ^^^
[INFO] [stdout]     |
[INFO] [stdout]     = help: enable feature `deref_patterns` instead and...
[INFO] [stdout] help: ...if possible just remove keyword `box`...
[INFO] [stdout]     |
[INFO] [stdout] 143 -         HfPlusNode::Union(box HfPlusNode::Persist(_), box HfPlusNode::Persist(_)) => {
[INFO] [stdout] 143 +         HfPlusNode::Union(HfPlusNode::Persist(_), box HfPlusNode::Persist(_)) => {
[INFO] [stdout]     |
[INFO] [stdout] help: ...otherwise replace it with an invocation of macro `deref`
[INFO] [stdout]     |
[INFO] [stdout] 143 -         HfPlusNode::Union(box HfPlusNode::Persist(_), box HfPlusNode::Persist(_)) => {
[INFO] [stdout] 143 +         HfPlusNode::Union(deref!(HfPlusNode::Persist(_)), box HfPlusNode::Persist(_)) => {
[INFO] [stdout]     |
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] error: `box` patterns have been removed (feature `box_patterns`)
[INFO] [stdout]    --> /opt/rustwide/cargo-home/registry/src/index.crates.io-1949cf8c6b5b557f/hydroflow_plus-0.9.0/src/persist_pullup.rs:143:55
[INFO] [stdout]     |
[INFO] [stdout] 143 |         HfPlusNode::Union(box HfPlusNode::Persist(_), box HfPlusNode::Persist(_)) => {
[INFO] [stdout]     |                                                       ^^^
[INFO] [stdout]     |
[INFO] [stdout]     = help: enable feature `deref_patterns` instead and...
[INFO] [stdout] help: ...if possible just remove keyword `box`...
[INFO] [stdout]     |
[INFO] [stdout] 143 -         HfPlusNode::Union(box HfPlusNode::Persist(_), box HfPlusNode::Persist(_)) => {
[INFO] [stdout] 143 +         HfPlusNode::Union(box HfPlusNode::Persist(_), HfPlusNode::Persist(_)) => {
[INFO] [stdout]     |
[INFO] [stdout] help: ...otherwise replace it with an invocation of macro `deref`
[INFO] [stdout]     |
[INFO] [stdout] 143 -         HfPlusNode::Union(box HfPlusNode::Persist(_), box HfPlusNode::Persist(_)) => {
[INFO] [stdout] 143 +         HfPlusNode::Union(box HfPlusNode::Persist(_), deref!(HfPlusNode::Persist(_))) => {
[INFO] [stdout]     |
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] error: `box` patterns have been removed (feature `box_patterns`)
[INFO] [stdout]    --> /opt/rustwide/cargo-home/registry/src/index.crates.io-1949cf8c6b5b557f/hydroflow_plus-0.9.0/src/persist_pullup.rs:145:17
[INFO] [stdout]     |
[INFO] [stdout] 145 |                 box HfPlusNode::Persist(left),
[INFO] [stdout]     |                 ^^^
[INFO] [stdout]     |
[INFO] [stdout]     = help: enable feature `deref_patterns` instead and...
[INFO] [stdout] help: ...if possible just remove keyword `box`...
[INFO] [stdout]     |
[INFO] [stdout] 145 -                 box HfPlusNode::Persist(left),
[INFO] [stdout] 145 +                 HfPlusNode::Persist(left),
[INFO] [stdout]     |
[INFO] [stdout] help: ...otherwise replace it with an invocation of macro `deref`
[INFO] [stdout]     |
[INFO] [stdout] 145 -                 box HfPlusNode::Persist(left),
[INFO] [stdout] 145 +                 deref!(HfPlusNode::Persist(left)),
[INFO] [stdout]     |
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] error: `box` patterns have been removed (feature `box_patterns`)
[INFO] [stdout]    --> /opt/rustwide/cargo-home/registry/src/index.crates.io-1949cf8c6b5b557f/hydroflow_plus-0.9.0/src/persist_pullup.rs:146:17
[INFO] [stdout]     |
[INFO] [stdout] 146 |                 box HfPlusNode::Persist(right),
[INFO] [stdout]     |                 ^^^
[INFO] [stdout]     |
[INFO] [stdout]     = help: enable feature `deref_patterns` instead and...
[INFO] [stdout] help: ...if possible just remove keyword `box`...
[INFO] [stdout]     |
[INFO] [stdout] 146 -                 box HfPlusNode::Persist(right),
[INFO] [stdout] 146 +                 HfPlusNode::Persist(right),
[INFO] [stdout]     |
[INFO] [stdout] help: ...otherwise replace it with an invocation of macro `deref`
[INFO] [stdout]     |
[INFO] [stdout] 146 -                 box HfPlusNode::Persist(right),
[INFO] [stdout] 146 +                 deref!(HfPlusNode::Persist(right)),
[INFO] [stdout]     |
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] error: `box` patterns have been removed (feature `box_patterns`)
[INFO] [stdout]    --> /opt/rustwide/cargo-home/registry/src/index.crates.io-1949cf8c6b5b557f/hydroflow_plus-0.9.0/src/persist_pullup.rs:155:34
[INFO] [stdout]     |
[INFO] [stdout] 155 |         HfPlusNode::CrossProduct(box HfPlusNode::Persist(_), box HfPlusNode::Persist(_)) => {
[INFO] [stdout]     |                                  ^^^
[INFO] [stdout]     |
[INFO] [stdout]     = help: enable feature `deref_patterns` instead and...
[INFO] [stdout] help: ...if possible just remove keyword `box`...
[INFO] [stdout]     |
[INFO] [stdout] 155 -         HfPlusNode::CrossProduct(box HfPlusNode::Persist(_), box HfPlusNode::Persist(_)) => {
[INFO] [stdout] 155 +         HfPlusNode::CrossProduct(HfPlusNode::Persist(_), box HfPlusNode::Persist(_)) => {
[INFO] [stdout]     |
[INFO] [stdout] help: ...otherwise replace it with an invocation of macro `deref`
[INFO] [stdout]     |
[INFO] [stdout] 155 -         HfPlusNode::CrossProduct(box HfPlusNode::Persist(_), box HfPlusNode::Persist(_)) => {
[INFO] [stdout] 155 +         HfPlusNode::CrossProduct(deref!(HfPlusNode::Persist(_)), box HfPlusNode::Persist(_)) => {
[INFO] [stdout]     |
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] error: `box` patterns have been removed (feature `box_patterns`)
[INFO] [stdout]    --> /opt/rustwide/cargo-home/registry/src/index.crates.io-1949cf8c6b5b557f/hydroflow_plus-0.9.0/src/persist_pullup.rs:155:62
[INFO] [stdout]     |
[INFO] [stdout] 155 |         HfPlusNode::CrossProduct(box HfPlusNode::Persist(_), box HfPlusNode::Persist(_)) => {
[INFO] [stdout]     |                                                              ^^^
[INFO] [stdout]     |
[INFO] [stdout]     = help: enable feature `deref_patterns` instead and...
[INFO] [stdout] help: ...if possible just remove keyword `box`...
[INFO] [stdout]     |
[INFO] [stdout] 155 -         HfPlusNode::CrossProduct(box HfPlusNode::Persist(_), box HfPlusNode::Persist(_)) => {
[INFO] [stdout] 155 +         HfPlusNode::CrossProduct(box HfPlusNode::Persist(_), HfPlusNode::Persist(_)) => {
[INFO] [stdout]     |
[INFO] [stdout] help: ...otherwise replace it with an invocation of macro `deref`
[INFO] [stdout]     |
[INFO] [stdout] 155 -         HfPlusNode::CrossProduct(box HfPlusNode::Persist(_), box HfPlusNode::Persist(_)) => {
[INFO] [stdout] 155 +         HfPlusNode::CrossProduct(box HfPlusNode::Persist(_), deref!(HfPlusNode::Persist(_))) => {
[INFO] [stdout]     |
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] error: `box` patterns have been removed (feature `box_patterns`)
[INFO] [stdout]    --> /opt/rustwide/cargo-home/registry/src/index.crates.io-1949cf8c6b5b557f/hydroflow_plus-0.9.0/src/persist_pullup.rs:157:17
[INFO] [stdout]     |
[INFO] [stdout] 157 |                 box HfPlusNode::Persist(left),
[INFO] [stdout]     |                 ^^^
[INFO] [stdout]     |
[INFO] [stdout]     = help: enable feature `deref_patterns` instead and...
[INFO] [stdout] help: ...if possible just remove keyword `box`...
[INFO] [stdout]     |
[INFO] [stdout] 157 -                 box HfPlusNode::Persist(left),
[INFO] [stdout] 157 +                 HfPlusNode::Persist(left),
[INFO] [stdout]     |
[INFO] [stdout] help: ...otherwise replace it with an invocation of macro `deref`
[INFO] [stdout]     |
[INFO] [stdout] 157 -                 box HfPlusNode::Persist(left),
[INFO] [stdout] 157 +                 deref!(HfPlusNode::Persist(left)),
[INFO] [stdout]     |
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] error: `box` patterns have been removed (feature `box_patterns`)
[INFO] [stdout]    --> /opt/rustwide/cargo-home/registry/src/index.crates.io-1949cf8c6b5b557f/hydroflow_plus-0.9.0/src/persist_pullup.rs:158:17
[INFO] [stdout]     |
[INFO] [stdout] 158 |                 box HfPlusNode::Persist(right),
[INFO] [stdout]     |                 ^^^
[INFO] [stdout]     |
[INFO] [stdout]     = help: enable feature `deref_patterns` instead and...
[INFO] [stdout] help: ...if possible just remove keyword `box`...
[INFO] [stdout]     |
[INFO] [stdout] 158 -                 box HfPlusNode::Persist(right),
[INFO] [stdout] 158 +                 HfPlusNode::Persist(right),
[INFO] [stdout]     |
[INFO] [stdout] help: ...otherwise replace it with an invocation of macro `deref`
[INFO] [stdout]     |
[INFO] [stdout] 158 -                 box HfPlusNode::Persist(right),
[INFO] [stdout] 158 +                 deref!(HfPlusNode::Persist(right)),
[INFO] [stdout]     |
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] error: `box` patterns have been removed (feature `box_patterns`)
[INFO] [stdout]    --> /opt/rustwide/cargo-home/registry/src/index.crates.io-1949cf8c6b5b557f/hydroflow_plus-0.9.0/src/persist_pullup.rs:172:26
[INFO] [stdout]     |
[INFO] [stdout] 172 |         HfPlusNode::Join(box HfPlusNode::Persist(_), box HfPlusNode::Persist(_)) => {
[INFO] [stdout]     |                          ^^^
[INFO] [stdout]     |
[INFO] [stdout]     = help: enable feature `deref_patterns` instead and...
[INFO] [stdout] help: ...if possible just remove keyword `box`...
[INFO] [stdout]     |
[INFO] [stdout] 172 -         HfPlusNode::Join(box HfPlusNode::Persist(_), box HfPlusNode::Persist(_)) => {
[INFO] [stdout] 172 +         HfPlusNode::Join(HfPlusNode::Persist(_), box HfPlusNode::Persist(_)) => {
[INFO] [stdout]     |
[INFO] [stdout] help: ...otherwise replace it with an invocation of macro `deref`
[INFO] [stdout]     |
[INFO] [stdout] 172 -         HfPlusNode::Join(box HfPlusNode::Persist(_), box HfPlusNode::Persist(_)) => {
[INFO] [stdout] 172 +         HfPlusNode::Join(deref!(HfPlusNode::Persist(_)), box HfPlusNode::Persist(_)) => {
[INFO] [stdout]     |
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] error: `box` patterns have been removed (feature `box_patterns`)
[INFO] [stdout]    --> /opt/rustwide/cargo-home/registry/src/index.crates.io-1949cf8c6b5b557f/hydroflow_plus-0.9.0/src/persist_pullup.rs:172:54
[INFO] [stdout]     |
[INFO] [stdout] 172 |         HfPlusNode::Join(box HfPlusNode::Persist(_), box HfPlusNode::Persist(_)) => {
[INFO] [stdout]     |                                                      ^^^
[INFO] [stdout]     |
[INFO] [stdout]     = help: enable feature `deref_patterns` instead and...
[INFO] [stdout] help: ...if possible just remove keyword `box`...
[INFO] [stdout]     |
[INFO] [stdout] 172 -         HfPlusNode::Join(box HfPlusNode::Persist(_), box HfPlusNode::Persist(_)) => {
[INFO] [stdout] 172 +         HfPlusNode::Join(box HfPlusNode::Persist(_), HfPlusNode::Persist(_)) => {
[INFO] [stdout]     |
[INFO] [stdout] help: ...otherwise replace it with an invocation of macro `deref`
[INFO] [stdout]     |
[INFO] [stdout] 172 -         HfPlusNode::Join(box HfPlusNode::Persist(_), box HfPlusNode::Persist(_)) => {
[INFO] [stdout] 172 +         HfPlusNode::Join(box HfPlusNode::Persist(_), deref!(HfPlusNode::Persist(_))) => {
[INFO] [stdout]     |
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] error: `box` patterns have been removed (feature `box_patterns`)
[INFO] [stdout]    --> /opt/rustwide/cargo-home/registry/src/index.crates.io-1949cf8c6b5b557f/hydroflow_plus-0.9.0/src/persist_pullup.rs:173:37
[INFO] [stdout]     |
[INFO] [stdout] 173 |             if let HfPlusNode::Join(box HfPlusNode::Persist(left), box HfPlusNode::Persist(right)) =
[INFO] [stdout]     |                                     ^^^
[INFO] [stdout]     |
[INFO] [stdout]     = help: enable feature `deref_patterns` instead and...
[INFO] [stdout] help: ...if possible just remove keyword `box`...
[INFO] [stdout]     |
[INFO] [stdout] 173 -             if let HfPlusNode::Join(box HfPlusNode::Persist(left), box HfPlusNode::Persist(right)) =
[INFO] [stdout] 173 +             if let HfPlusNode::Join(HfPlusNode::Persist(left), box HfPlusNode::Persist(right)) =
[INFO] [stdout]     |
[INFO] [stdout] help: ...otherwise replace it with an invocation of macro `deref`
[INFO] [stdout]     |
[INFO] [stdout] 173 -             if let HfPlusNode::Join(box HfPlusNode::Persist(left), box HfPlusNode::Persist(right)) =
[INFO] [stdout] 173 +             if let HfPlusNode::Join(deref!(HfPlusNode::Persist(left)), box HfPlusNode::Persist(right)) =
[INFO] [stdout]     |
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] error: `box` patterns have been removed (feature `box_patterns`)
[INFO] [stdout]    --> /opt/rustwide/cargo-home/registry/src/index.crates.io-1949cf8c6b5b557f/hydroflow_plus-0.9.0/src/persist_pullup.rs:173:68
[INFO] [stdout]     |
[INFO] [stdout] 173 |             if let HfPlusNode::Join(box HfPlusNode::Persist(left), box HfPlusNode::Persist(right)) =
[INFO] [stdout]     |                                                                    ^^^
[INFO] [stdout]     |
[INFO] [stdout]     = help: enable feature `deref_patterns` instead and...
[INFO] [stdout] help: ...if possible just remove keyword `box`...
[INFO] [stdout]     |
[INFO] [stdout] 173 -             if let HfPlusNode::Join(box HfPlusNode::Persist(left), box HfPlusNode::Persist(right)) =
[INFO] [stdout] 173 +             if let HfPlusNode::Join(box HfPlusNode::Persist(left), HfPlusNode::Persist(right)) =
[INFO] [stdout]     |
[INFO] [stdout] help: ...otherwise replace it with an invocation of macro `deref`
[INFO] [stdout]     |
[INFO] [stdout] 173 -             if let HfPlusNode::Join(box HfPlusNode::Persist(left), box HfPlusNode::Persist(right)) =
[INFO] [stdout] 173 +             if let HfPlusNode::Join(box HfPlusNode::Persist(left), deref!(HfPlusNode::Persist(right))) =
[INFO] [stdout]     |
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] error: `box` patterns have been removed (feature `box_patterns`)
[INFO] [stdout]  --> /opt/rustwide/target/debug/build/hydroflow_plus/5672655b657d1e44/out/lib_pub.rs:1:91783
[INFO] [stdout]   |
[INFO] [stdout] 1 | ...d_tees) , seen_tees ,) ; match node { HfPlusNode :: Unpersist (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Unpersist ...
[INFO] [stdout]   |                                                                   ^^^
[INFO] [stdout]   |
[INFO] [stdout]   = help: enable feature `deref_patterns` instead and...
[INFO] [stdout] help: ...if possible just remove keyword `box`...
[INFO] [stdout]   |
[INFO] [stdout] 1 - pub use std :: collections :: BTreeMap ; pub use std :: marker :: PhantomData ; pub use hydroflow :: scheduled :: context :: Context ; pub use hydroflow :: scheduled :: graph :: Hydroflow ; pub use hydroflow :: * ; pub use lang :: graph :: { partition_graph , HydroflowGraph } ; pub use proc_macro2 :: TokenStream ; pub use quote :: quote ; pub use stageleft :: runtime_support :: FreeVariable ; pub use stageleft :: Quoted ; pub mod runtime_support { pub use bincode ; } pub mod stream { pub use std :: cell :: RefCell ; pub use std :: hash :: Hash ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow :: bytes :: Bytes ; pub use hydroflow :: futures :: Sink ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: quote ; pub use serde :: de :: DeserializeOwned ; pub use serde :: Serialize ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use syn :: parse_quote ; pub use crate :: builder :: { ClusterIds , FlowLeaves } ; pub use crate :: cycle :: { CycleCollection , CycleComplete } ; pub use crate :: ir :: { DebugInstantiate , HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { CanSend , Location , LocationId } ; pub use crate :: { Cluster , Optional , Singleton } ; pub use crate :: stream :: Unbounded ; pub use crate :: stream :: Bounded ; pub use crate :: stream :: NoTick ; pub use crate :: stream :: Tick ; pub use crate :: stream :: Stream ; # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Stream { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Stream < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Stream { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , C , N > > ,) -> Stream < 'a , (T , O) , W , C , N > where O : Clone , { let other : Optional < 'a , O , Bounded , C , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn cross_product < O > (self , other : Stream < 'a , O , W , C , N >) -> Stream < 'a , (T , O) , W , C , N > where T : Clone , O : Clone , { if self . location_kind != other . location_kind { panic ! ("cross_product must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossProduct (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn union (self , other : Stream < 'a , T , W , C , N >) -> Stream < 'a , T , W , C , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn dest_sink < S : Unpin + Sink < T > + 'a > (self , sink : impl Quoted < 'a , S >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: DestSink { sink : sink . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn first (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } # [doc = " Allow this stream through if the other stream has elements, otherwise the output is empty."] pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } # [doc = " Allow this stream through if the other stream is empty, otherwise the output is empty."] pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn enumerate (self) -> Stream < 'a , (usize , T) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Enumerate (Box :: new (self . ir_node . into_inner ())) ,) } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn sort (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Ord , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Sort (Box :: new (self . ir_node . into_inner ())) ,) } pub fn count (self) -> Singleton < 'a , usize , Bounded , Tick , N > { self . fold (q ! (|| 0usize) , q ! (| count , _ | * count += 1)) } pub fn delta (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } pub fn unique (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Eq + Hash , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unique (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn tick_batch (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_prefix (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { self . tick_batch () . persist () } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn for_each < F : Fn (T) + 'a > (self , f : impl IntoQuotedMut < 'a , F >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: ForEach { input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , f : f . splice () . into () , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Unbounded , NoTick , N > { pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . tick_batch () . continue_if (samples . first ()) . all_ticks () } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Unbounded , NoTick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , C , N : Location > Stream < 'a , T , Bounded , C , N > { pub fn filter_not_in (self , other : Stream < 'a , T , Bounded , C , N >) -> Stream < 'a , T , Bounded , C , N > where T : Eq + Hash , { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Difference (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Stream < 'a , & T , W , C , N > { pub fn cloned (self) -> Stream < 'a , T , W , C , N > { self . map (q ! (| d | d . clone ())) } } # [cfg (stageleft_macro)] impl < 'a , K , V1 , W , C , N : Location > Stream < 'a , (K , V1) , W , C , N > { pub fn join < W2 , V2 > (self , n : Stream < 'a , (K , V2) , W2 , C , N > ,) -> Stream < 'a , (K , (V1 , V2)) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Join (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } pub fn anti_join < W2 > (self , n : Stream < 'a , K , W2 , C , N >) -> Stream < 'a , (K , V1) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("anti_join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: AntiJoin (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , K : Eq + Hash , V , N : Location > Stream < 'a , (K , V) , Bounded , Tick , N > { pub fn fold_keyed < A , I : Fn () -> A + 'a , F : Fn (& mut A , V) + 'a > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , A) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FoldKeyed { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce_keyed < F : Fn (& mut V , V) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , V) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: ReduceKeyed { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } pub fn get_this_crate () -> TokenStream { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , Span :: call_site ()) ; quote ! { # ident } } } } pub fn serialize_bincode < T : Serialize > (is_demux : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if is_demux { parse_quote ! { map (| (id , data) | { (id , # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into ()) }) } } else { parse_quote ! { map (| data | { # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into () }) } } } pub fn deserialize_bincode < T : DeserializeOwned > (tagged : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if tagged { parse_quote ! { map (| res | { let (id , b) = res . unwrap () ; (id , # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& b) . unwrap ()) }) } } else { parse_quote ! { map (| res | { # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& res . unwrap ()) . unwrap () }) } } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn send_bincode < N2 : Location , CoreType > (self , other : & N2 ,) -> Stream < 'a , N :: Out < CoreType > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T > , CoreType : Serialize + DeserializeOwned , { let serialize_pipeline = Some (serialize_bincode :: < CoreType > (N :: is_demux ())) ; let deserialize_pipeline = Some (deserialize_bincode :: < CoreType > (N :: is_tagged ())) ; Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bytes < N2 : Location > (self , other : & N2 ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T > , { Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline : None , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline : if N :: is_tagged () { Some (parse_quote ! (map (| (id , b) | (id , b . unwrap () . freeze ())))) } else { Some (parse_quote ! (map (| b | b . unwrap () . freeze ()))) } , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bincode_interleaved < N2 : Location , Tag , CoreType > (self , other : & N2 ,) -> Stream < 'a , CoreType , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T , Out < CoreType > = (Tag , CoreType) > , CoreType : Serialize + DeserializeOwned , { self . send_bincode :: < N2 , CoreType > (other) . map (q ! (| (_ , b) | b)) } pub fn send_bytes_interleaved < N2 : Location , Tag > (self , other : & N2 ,) -> Stream < 'a , Bytes , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T , Out < Bytes > = (Tag , Bytes) > , { self . send_bytes :: < N2 > (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bincode < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < T > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) > , T : Clone + Serialize + DeserializeOwned , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bincode (other) } pub fn broadcast_bincode_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , T , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) , Out < T > = (Tag , T) > + 'a , T : Clone + Serialize + DeserializeOwned , { self . broadcast_bincode (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bytes < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) > + 'a , T : Clone , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bytes (other) } pub fn broadcast_bytes_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , Bytes , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) , Out < Bytes > = (Tag , Bytes) > + 'a , T : Clone , { self . broadcast_bytes (other) . map (q ! (| (_ , b) | b)) } } } pub use stream :: { Bounded , NoTick , Stream , Tick , Unbounded } ; pub mod singleton { pub use std :: cell :: RefCell ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use crate :: builder :: FlowLeaves ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial , CycleComplete } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: Stream ; pub use crate :: singleton :: CrossResult ; # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Singleton < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Singleton :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } pub use crate :: singleton :: Singleton ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Singleton { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleComplete < 'a > for Singleton < 'a , T , Bounded , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleCollectionWithInitial < 'a > for Singleton < 'a , T , Bounded , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , initial : Self , l : LocationId ,) -> Self { Singleton :: new (l , ir_leaves , HfPlusNode :: Union (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , }) , initial . ir_node . into_inner () . into () ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Singleton < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Singleton { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , U , W , C , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (Self :: other_ir_node (other)) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Singleton < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CrossSingleton (Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , Box :: new (HfPlusNode :: Unpersist (Box :: new (Self :: other_ir_node (other)))) ,))) ,) } } pub use crate :: singleton :: Optional ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Optional { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } pub fn some (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: new (singleton . location_kind , singleton . ir_leaves , singleton . ir_node . into_inner () ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > From < Singleton < 'a , T , W , C , N > > for Optional < 'a , T , W , C , N > { fn from (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: some (singleton) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Optional < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Optional { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn into_stream (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , Tick , N > > ,) -> Optional < 'a , (T , O) , Bounded , Tick , N > where O : Clone , { let other : Optional < 'a , O , Bounded , Tick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn union (self , other : Optional < 'a , T , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Optional < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_samples (self) -> Stream < 'a , T , Unbounded , NoTick , N > { self . latest_tick () . all_ticks () } pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . latest_tick () . continue_if (samples . first ()) . latest () . tick_samples () } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Unbounded , NoTick , N > > ,) -> Optional < 'a , (T , O) , Unbounded , NoTick , N > where O : Clone , { let other : Optional < 'a , O , Unbounded , NoTick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } self . latest_tick () . cross_singleton (other . latest_tick ()) . latest () } } } pub use singleton :: { Optional , Singleton } ; pub mod location { pub use std :: marker :: PhantomData ; pub use crate :: location :: LocationId ; pub use crate :: location :: Location ; pub use crate :: location :: Process ; # [cfg (stageleft_macro)] impl < P > Clone for Process < P > { fn clone (& self) -> Self { Process { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < P > Location for Process < P > { fn id (& self) -> LocationId { LocationId :: Process (self . id) } } pub use crate :: location :: Cluster ; # [cfg (stageleft_macro)] impl < C > Clone for Cluster < C > { fn clone (& self) -> Self { Cluster { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < C > Location for Cluster < C > { fn id (& self) -> LocationId { LocationId :: Cluster (self . id) } } pub use crate :: location :: CanSend ; # [cfg (stageleft_macro)] impl < P1 , P2 > CanSend < Process < P2 > > for Process < P1 > { type In < T > = T ; type Out < T > = T ; fn is_demux () -> bool { false } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < P1 , C2 > CanSend < Cluster < C2 > > for Process < P1 > { type In < T > = (u32 , T) ; type Out < T > = T ; fn is_demux () -> bool { true } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < C1 , P2 > CanSend < Process < P2 > > for Cluster < C1 > { type In < T > = T ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { false } fn is_tagged () -> bool { true } } # [cfg (stageleft_macro)] impl < C1 , C2 > CanSend < Cluster < C2 > > for Cluster < C1 > { type In < T > = (u32 , T) ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { true } fn is_tagged () -> bool { true } } } pub use location :: { Cluster , Process } ; pub mod deploy { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use stageleft :: Quoted ; pub mod graphs { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use super :: { LocalDeploy , Node , ProcessSpec } ; pub use crate :: deploy :: graphs :: SingleProcessGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for SingleProcessGraph { type Process = SingleNode ; type Cluster = SingleNode ; type Meta = () ; type GraphId = () ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { SingleNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { SingleNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , SingleProcessGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> SingleNode { SingleNode { } } } pub use crate :: deploy :: graphs :: SingleNode ; # [cfg (stageleft_macro)] impl Node for SingleNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } pub use crate :: deploy :: graphs :: MultiGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for MultiGraph { type Process = MultiNode ; type Cluster = MultiNode ; type Meta = () ; type GraphId = usize ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { MultiNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { MultiNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , MultiGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> MultiNode { MultiNode { } } } pub use crate :: deploy :: graphs :: MultiNode ; # [cfg (stageleft_macro)] impl Node for MultiNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } } pub use graphs :: * ; pub use crate :: deploy :: LocalDeploy ; pub use crate :: deploy :: Deploy ; # [cfg (stageleft_macro)] impl < 'a , T : Deploy < 'a , Process = N , Cluster = C , Meta = M , GraphId = R > , N : Node < Meta = M > , C : Node < Meta = M > , M : Default , R , > LocalDeploy < 'a > for T { type Process = N ; type Cluster = C ; type Meta = M ; type GraphId = R ; fn has_trivial_node () -> bool { < T as Deploy < 'a > > :: has_trivial_node () } fn trivial_process (id : usize) -> Self :: Process { < T as Deploy < 'a > > :: trivial_process (id) } fn trivial_cluster (id : usize) -> Self :: Cluster { < T as Deploy < 'a > > :: trivail_cluster (id) } } pub use crate :: deploy :: ProcessSpec ; pub use crate :: deploy :: ClusterSpec ; pub use crate :: deploy :: Node ; } pub use deploy :: { ClusterSpec , Deploy , ProcessSpec } ; pub mod cycle { pub use std :: marker :: PhantomData ; pub use crate :: builder :: FlowLeaves ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: cycle :: CycleComplete ; pub use crate :: cycle :: CycleCollection ; pub use crate :: cycle :: CycleCollectionWithInitial ; pub use crate :: cycle :: HfCycle ; # [cfg (stageleft_macro)] impl < 'a , S : CycleComplete < 'a > > HfCycle < 'a , S > { pub fn complete (self , stream : S) { let ident = self . ident ; S :: complete (stream , ident) } } } pub use cycle :: HfCycle ; pub mod builder { pub use std :: cell :: RefCell ; pub use std :: collections :: HashMap ; pub use std :: marker :: PhantomData ; pub use std :: rc :: Rc ; pub use std :: time :: Duration ; pub use hydroflow :: futures :: stream :: Stream as FuturesStream ; pub use hydroflow :: { tokio , tokio_stream } ; pub use internal :: TokenStream ; pub use proc_macro2 :: Span ; pub use quote :: quote ; pub use runtime_support :: FreeVariable ; pub use stageleft :: * ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Cluster , Location , LocationId , Process } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: { HfCycle , Optional , RuntimeContext , Singleton , Stream } ; pub mod built { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use hydroflow_lang :: graph :: { eliminate_extra_unions_tees , HydroflowGraph } ; pub use super :: deploy :: { DeployFlow , DeployResult } ; pub use crate :: deploy :: { ClusterSpec , Deploy , LocalDeploy , ProcessSpec } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Cluster , Process } ; pub use crate :: HfCompiled ; pub use crate :: builder :: built :: BuiltFlow ; # [cfg (stageleft_macro)] impl < 'a > Drop for BuiltFlow < 'a > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped BuiltFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn ir (& self) -> & Vec < HfPlusLeaf < 'a > > { & self . ir } pub fn optimize_with (mut self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> BuiltFlow < 'a > { self . used = true ; BuiltFlow { ir : f (std :: mem :: take (& mut self . ir)) , processes : std :: mem :: take (& mut self . processes) , clusters : std :: mem :: take (& mut self . clusters) , used : false , _phantom : PhantomData , } } } pub fn build_inner (ir : & mut Vec < HfPlusLeaf >) -> BTreeMap < usize , HydroflowGraph > { let mut builders = BTreeMap :: new () ; let mut built_tees = HashMap :: new () ; let mut next_stmt_id = 0 ; for leaf in ir { leaf . emit (& mut builders , & mut built_tees , & mut next_stmt_id) ; } builders . into_iter () . map (| (k , v) | { let (mut flat_graph , _ , _) = v . build () ; eliminate_extra_unions_tees (& mut flat_graph) ; (k , flat_graph) }) . collect () } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn compile_no_network < D : LocalDeploy < 'a > > (mut self) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; HfCompiled { hydroflow_ir : build_inner (& mut self . ir) , extra_stmts : BTreeMap :: new () , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> BuiltFlow < 'a > { self . optimize_with (crate :: persist_pullup :: persist_pullup) } fn into_deploy < D : LocalDeploy < 'a > > (mut self) -> DeployFlow < 'a , D > { self . used = true ; let processes = if D :: has_trivial_node () { self . processes . iter () . map (| id | (* id , D :: trivial_process (* id))) . collect () } else { HashMap :: new () } ; let clusters = if D :: has_trivial_node () { self . clusters . iter () . map (| id | (* id , D :: trivial_cluster (* id))) . collect () } else { HashMap :: new () } ; DeployFlow { ir : std :: mem :: take (& mut self . ir) , nodes : processes , clusters , used : false , _phantom : PhantomData , } } pub fn with_process < P , D : LocalDeploy < 'a > > (self , process : & Process < P > , spec : impl ProcessSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_process (process , spec) } pub fn with_cluster < C , D : LocalDeploy < 'a > > (self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_cluster (cluster , spec) } pub fn compile < D : Deploy < 'a > + 'a > (self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . into_deploy :: < D > () . compile (env) } pub fn deploy < D : Deploy < 'a , CompileEnv = () > + 'a > (self , env : & mut D :: InstantiateEnv ,) -> DeployResult < 'a , D > { self . into_deploy :: < D > () . deploy (env) } } } pub mod deploy { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use proc_macro2 :: Span ; pub use stageleft :: Quoted ; pub use super :: built :: build_inner ; pub use crate :: deploy :: { LocalDeploy , Node } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: { Cluster , ClusterSpec , Deploy , HfCompiled , Process , ProcessSpec } ; pub use crate :: builder :: deploy :: DeployFlow ; # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > Drop for DeployFlow < 'a , D > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped DeployFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > DeployFlow < 'a , D > { pub fn with_process < P > (mut self , process : & Process < P > , spec : impl ProcessSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < P > () . to_string () ; self . nodes . insert (process . id , spec . build (process . id , & tag_name)) ; self } pub fn with_cluster < C > (mut self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < C > () . to_string () ; self . clusters . insert (cluster . id , spec . build (cluster . id , & tag_name)) ; self } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployFlow < 'a , D > { pub fn compile (mut self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; let mut seen_tees : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | leaf . compile_network :: < D > (env , & mut seen_tees , & self . nodes , & self . clusters)) . collect () ; let extra_stmts = self . extra_stmts (env) ; HfCompiled { hydroflow_ir : build_inner (& mut ir_leaves_networked) , extra_stmts , _phantom : PhantomData , } } fn extra_stmts (& self , env : & < D as Deploy < 'a > > :: CompileEnv) -> BTreeMap < usize , Vec < syn :: Stmt > > { let all_locations_count = self . nodes . len () + self . clusters . len () ; let mut extra_stmts : BTreeMap < usize , Vec < syn :: Stmt > > = BTreeMap :: new () ; for & c_id in self . clusters . keys () { let self_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , c_id) , Span :: call_site () ,) ; let self_id_expr = D :: cluster_self_id (env) . splice () ; extra_stmts . entry (c_id) . or_default () . push (syn :: parse_quote ! { let # self_id_ident = # self_id_expr ; }) ; for other_location in 0 .. all_locations_count { let other_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , c_id) , Span :: call_site () ,) ; let other_id_expr = D :: cluster_ids (env , c_id) . splice () ; extra_stmts . entry (other_location) . or_default () . push (syn :: parse_quote ! { let # other_id_ident = # other_id_expr ; }) ; } } extra_stmts } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a , CompileEnv = () > > DeployFlow < 'a , D > { # [must_use] pub fn deploy (mut self , env : & mut D :: InstantiateEnv) -> DeployResult < 'a , D > { self . used = true ; let mut seen_tees_instantiate : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | { leaf . compile_network :: < D > (& () , & mut seen_tees_instantiate , & self . nodes , & self . clusters ,) }) . collect () ; let mut compiled = build_inner (& mut ir_leaves_networked) ; let mut extra_stmts = self . extra_stmts (& ()) ; let mut meta = D :: Meta :: default () ; let (mut processes , mut clusters) = (std :: mem :: take (& mut self . nodes) . into_iter () . map (| (node_id , node) | { node . instantiate (env , & mut meta , compiled . remove (& node_id) . unwrap () , extra_stmts . remove (& node_id) . unwrap_or_default () ,) ; (node_id , node) }) . collect :: < HashMap < _ , _ > > () , std :: mem :: take (& mut self . clusters) . into_iter () . map (| (cluster_id , cluster) | { cluster . instantiate (env , & mut meta , compiled . remove (& cluster_id) . unwrap () , extra_stmts . remove (& cluster_id) . unwrap_or_default () ,) ; (cluster_id , cluster) }) . collect :: < HashMap < _ , _ > > () ,) ; for node in processes . values_mut () { node . update_meta (& meta) ; } for cluster in clusters . values_mut () { cluster . update_meta (& meta) ; } let mut seen_tees_connect = HashMap :: new () ; for leaf in ir_leaves_networked { leaf . connect_network (& mut seen_tees_connect) ; } DeployResult { processes , clusters , } } } pub use crate :: builder :: deploy :: DeployResult ; # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployResult < 'a , D > { pub fn get_process < P > (& self , p : & Process < P >) -> & D :: Process { let id = match p . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . processes . get (& id) . unwrap () } pub fn get_cluster < C > (& self , c : & Cluster < C >) -> & D :: Cluster { let id = match c . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . clusters . get (& id) . unwrap () } } } # [doc = " Tracks the leaves of the dataflow IR. This is referenced by"] # [doc = " `Stream` and `HfCycle` to build the IR. The inner option will"] # [doc = " be set to `None` when this builder is finalized."] pub type FlowLeaves < 'a > = Rc < RefCell < Option < Vec < HfPlusLeaf < 'a > > > > > ; pub use crate :: builder :: ClusterIds ; # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Vec < u32 > > for ClusterIds < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , & 'a Vec < u32 > > for ClusterIds < 'a > { } # [derive (Copy , Clone)] pub struct ClusterSelfId < 'a > { pub id : usize , pub _phantom : PhantomData < & 'a mut & 'a u32 > , } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < u32 > for ClusterSelfId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , u32 > for ClusterSelfId < 'a > { } pub use crate :: builder :: FlowBuilder ; # [cfg (stageleft_macro)] impl < 'a > Drop for FlowBuilder < 'a > { fn drop (& mut self) { if ! self . finalized { panic ! ("Dropped FlowBuilder without finalizing, you may have forgotten to call `with_default_optimize`, `optimize_with`, or `finalize`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > QuotedContext for FlowBuilder < 'a > { fn create () -> Self { FlowBuilder :: new () } } # [cfg (stageleft_macro)] impl < 'a > FlowBuilder < 'a > { # [allow (clippy :: new_without_default)] pub fn new () -> FlowBuilder < 'a > { FlowBuilder { ir_leaves : Rc :: new (RefCell :: new (Some (Vec :: new ()))) , nodes : RefCell :: new (vec ! []) , clusters : RefCell :: new (vec ! []) , cycle_ids : RefCell :: new (HashMap :: new ()) , next_node_id : RefCell :: new (0) , finalized : false , _phantom : PhantomData , } } pub fn finalize (mut self) -> built :: BuiltFlow < 'a > { self . finalized = true ; built :: BuiltFlow { ir : self . ir_leaves . borrow_mut () . take () . unwrap () , processes : self . nodes . replace (vec ! []) , clusters : self . clusters . replace (vec ! []) , used : false , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> built :: BuiltFlow < 'a > { self . finalize () . with_default_optimize () } pub fn optimize_with (self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> built :: BuiltFlow < 'a > { self . finalize () . optimize_with (f) } pub fn ir_leaves (& self) -> & FlowLeaves < 'a > { & self . ir_leaves } pub fn process < P > (& self) -> Process < P > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . nodes . borrow_mut () . push (id) ; Process { id , _phantom : PhantomData , } } pub fn cluster < C > (& self) -> Cluster < C > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . clusters . borrow_mut () . push (id) ; Cluster { id , _phantom : PhantomData , } } pub fn runtime_context (& self) -> RuntimeContext < 'a > { RuntimeContext { _phantom : PhantomData , } } pub fn cluster_members < C > (& self , cluster : & Cluster < C > ,) -> impl Quoted < 'a , & 'a Vec < u32 > > + Copy + 'a { ClusterIds { id : cluster . id , _phantom : PhantomData , } } pub fn cluster_self_id < C > (& self , cluster : & Cluster < C >) -> impl Quoted < 'a , u32 > + Copy + 'a { ClusterSelfId { id : cluster . id , _phantom : PhantomData , } } pub fn spin < L : Location > (& self , on : & L) -> Stream < 'a , () , Unbounded , NoTick , L > { Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Spin () , location_kind : on . id () , })) ,) } pub fn spin_batch < L : Location > (& self , on : & L , batch_size : impl Quoted < 'a , usize > + Copy + 'a ,) -> Stream < 'a , () , Bounded , Tick , L > { self . spin (on) . flat_map (q ! (move | _ | 0 .. batch_size)) . map (q ! (| _ | ())) . tick_batch () } pub fn source_stream < T , E : FuturesStream < Item = T > + Unpin , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Unbounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Stream (e . into ()) , location_kind : on . id () , })) ,) } pub fn source_iter < T , E : IntoIterator < Item = T > , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Bounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , })) ,) } pub fn singleton < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Singleton < 'a , T , Bounded , NoTick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Singleton :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,)))) ,) } pub fn singleton_first_tick < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Optional < 'a , T , Bounded , Tick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,) } pub fn source_interval < L : Location > (& self , on : & L , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , () , Unbounded , NoTick , L > { let interval = interval . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : on . id () , })) ,) } pub fn source_interval_delayed < L : Location > (& self , on : & L , delay : impl Quoted < 'a , Duration > + Copy + 'a , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , tokio :: time :: Instant , Unbounded , NoTick , L > { self . source_stream (on , q ! (tokio_stream :: wrappers :: IntervalStream :: new (tokio :: time :: interval_at (tokio :: time :: Instant :: now () + delay , interval))) ,) . tick_batch () . first () . latest () } pub fn cycle < S : CycleCollection < 'a > > (& self , on : & S :: Location) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , on . id ()) ,) } pub fn cycle_with_initial < S : CycleCollectionWithInitial < 'a > > (& self , on : & S :: Location , initial : S ,) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , initial , on . id ()) ,) } } } pub use builder :: FlowBuilder ; pub mod ir { pub use core :: panic ; pub use std :: cell :: RefCell ; pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow_lang :: graph :: FlatGraphBuilder ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: ToTokens ; pub use syn :: parse_quote ; pub use crate :: deploy :: Deploy ; pub use crate :: location :: LocationId ; pub use crate :: ir :: DebugExpr ; # [cfg (stageleft_macro)] impl From < syn :: Expr > for DebugExpr { fn from (expr : syn :: Expr) -> DebugExpr { DebugExpr (expr) } } # [cfg (stageleft_macro)] impl Deref for DebugExpr { type Target = syn :: Expr ; fn deref (& self) -> & Self :: Target { & self . 0 } } # [cfg (stageleft_macro)] impl ToTokens for DebugExpr { fn to_tokens (& self , tokens : & mut TokenStream) { self . 0 . to_tokens (tokens) ; } } # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugExpr { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "{}" , self . 0 . to_token_stream ()) } } pub use crate :: ir :: DebugInstantiate ; # [cfg (stageleft_macro)] impl < 'a > std :: fmt :: Debug for DebugInstantiate < 'a > { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<network instantiate>") } } pub use crate :: ir :: DebugPipelineFn ; # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugPipelineFn { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<function>") } } pub use crate :: ir :: HfPlusSource ; pub use crate :: ir :: HfPlusLeaf ; # [cfg (stageleft_macro)] impl < 'a > HfPlusLeaf < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . compile_network :: < D > (compile_env , s , nodes , clusters) ; } , seen_tees ,) } pub fn connect_network (self , seen_tees : & mut SeenTees < 'a >) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . connect_network (s) ; } , seen_tees ,) } pub fn transform_children (self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) -> HfPlusLeaf < 'a > { match self { HfPlusLeaf :: ForEach { f , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: ForEach { f , input } } HfPlusLeaf :: DestSink { sink , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: DestSink { sink , input } } HfPlusLeaf :: CycleSink { ident , location_kind , mut input , } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: CycleSink { ident , location_kind , input , } } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) { match self { HfPlusLeaf :: ForEach { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> for_each (# f) ; }) ; } HfPlusLeaf :: DestSink { sink , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink) ; }) ; } HfPlusLeaf :: CycleSink { ident , location_kind , input , } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; assert_eq ! (input_location_id , * location_id , "cycle_sink location mismatch") ; graph_builders . entry (* location_id) . or_default () . add_statement (parse_quote ! { # ident = # input_ident ; }) ; } } } } pub use crate :: ir :: HfPlusNode ; pub type SeenTees < 'a > = HashMap < * const RefCell < HfPlusNode < 'a > > , Rc < RefCell < HfPlusNode < 'a > > > > ; # [cfg (stageleft_macro)] impl < 'a > HfPlusNode < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (& mut self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) { self . transform_children (| n , s | n . compile_network :: < D > (compile_env , s , nodes , clusters) , seen_tees ,) ; if let HfPlusNode :: Network { from_location , to_location , instantiate_fn , .. } = self { let (sink_expr , source_expr , connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { let ((sink , source) , connect_fn) = match (from_location , to_location) { (LocationId :: Process (from) , LocationId :: Process (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: o2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Process (from) , LocationId :: Cluster (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: o2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Process (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: m2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Cluster (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: m2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } } ; (sink , source , connect_fn) } DebugInstantiate :: Finalized (_ , _ , _) => panic ! ("network already finalized") , } ; * instantiate_fn = DebugInstantiate :: Finalized (sink_expr , source_expr , connect_fn) ; } } pub fn connect_network (& mut self , seen_tees : & mut SeenTees < 'a >) { self . transform_children (| n , s | n . connect_network (s) , seen_tees) ; if let HfPlusNode :: Network { instantiate_fn , .. } = self { match instantiate_fn { DebugInstantiate :: Building () => panic ! ("network not built") , DebugInstantiate :: Finalized (_ , _ , ref connect_fn) => { connect_fn () ; } } } } pub fn transform_children (& mut self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) { match self { HfPlusNode :: Placeholder => { panic ! () ; } HfPlusNode :: Source { .. } => { } HfPlusNode :: CycleSource { .. } => { } HfPlusNode :: Tee { inner } => { if let Some (transformed) = seen_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { * inner = transformed . clone () ; } else { let transformed_cell = Rc :: new (RefCell :: new (HfPlusNode :: Placeholder)) ; seen_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , transformed_cell . clone () ,) ; let mut orig = inner . replace (HfPlusNode :: Placeholder) ; transform (& mut orig , seen_tees) ; * transformed_cell . borrow_mut () = orig ; * inner = transformed_cell ; } } HfPlusNode :: Persist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Unpersist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Delta (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Union (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossProduct (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossSingleton (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Join (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Difference (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: AntiJoin (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Map { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FlatMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Filter { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FilterMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Sort (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: DeferTick (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Enumerate (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Inspect { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Unique (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Fold { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FoldKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Reduce { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: ReduceKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Network { input , .. } => { transform (input . as_mut () , seen_tees) ; } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) -> (syn :: Ident , usize) { match self { HfPlusNode :: Placeholder => { panic ! () } HfPlusNode :: Persist (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let persist_id = * next_stmt_id ; * next_stmt_id += 1 ; let persist_ident = syn :: Ident :: new (& format ! ("stream_{}" , persist_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # persist_ident = # inner_ident -> persist ::<'static > () ; }) ; (persist_ident , location) } HfPlusNode :: Unpersist (_) => { panic ! ("Unpersist is a marker node and should have been optimized away. This is likely a compiler bug.") } HfPlusNode :: Delta (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let delta_id = * next_stmt_id ; * next_stmt_id += 1 ; let delta_ident = syn :: Ident :: new (& format ! ("stream_{}" , delta_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # delta_ident = # inner_ident -> multiset_delta () ; }) ; (delta_ident , location) } HfPlusNode :: Source { source , location_kind , } => { let source_id = * next_stmt_id ; * next_stmt_id += 1 ; let source_ident = syn :: Ident :: new (& format ! ("stream_{}" , source_id) , Span :: call_site ()) ; let source_stmt = match source { HfPlusSource :: Stream (expr) => { parse_quote ! { # source_ident = source_stream (# expr) ; } } HfPlusSource :: Iter (expr) => { parse_quote ! { # source_ident = source_iter (# expr) ; } } HfPlusSource :: Interval (expr) => { parse_quote ! { # source_ident = source_interval (# expr) ; } } HfPlusSource :: Spin () => { parse_quote ! { # source_ident = spin () ; } } } ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; graph_builders . entry (* location_id) . or_default () . add_statement (source_stmt) ; (source_ident , * location_id) } HfPlusNode :: CycleSource { ident , location_kind , } => { let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; (ident . clone () , * location_id) } HfPlusNode :: Tee { inner } => { if let Some (ret) = built_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { ret . clone () } else { let (inner_ident , inner_location_id) = inner . borrow () . emit (graph_builders , built_tees , next_stmt_id) ; let tee_id = * next_stmt_id ; * next_stmt_id += 1 ; let tee_ident = syn :: Ident :: new (& format ! ("stream_{}" , tee_id) , Span :: call_site ()) ; let builder = graph_builders . entry (inner_location_id) . or_default () ; builder . add_statement (parse_quote ! { # tee_ident = # inner_ident -> tee () ; }) ; built_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , (tee_ident . clone () , inner_location_id) ,) ; (tee_ident , inner_location_id) } } HfPlusNode :: Union (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "union inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let union_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # union_ident = union () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [0] # union_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # union_ident ; }) ; (union_ident , left_location_id) } HfPlusNode :: CrossSingleton (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "cross_singleton inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let cross_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # cross_ident = cross_singleton () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [input] # cross_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [single] # cross_ident ; }) ; (cross_ident , left_location_id) } HfPlusNode :: CrossProduct (..) | HfPlusNode :: Join (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: CrossProduct (..)) { parse_quote ! (cross_join_multiset) } else { parse_quote ! (join_multiset) } ; let (HfPlusNode :: CrossProduct (left , right) | HfPlusNode :: Join (left , right)) = self else { unreachable ! () } ; let (left_inner , left_was_persist) = if let HfPlusNode :: Persist (left) = left . as_ref () { (left , true) } else { (left , false) } ; let (right_inner , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left_inner . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right_inner . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "join / cross product inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; match (left_was_persist , right_was_persist) { (true , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'static > () ; }) ; } (true , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'tick > () ; }) ; } (false , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } (false , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } } ; builder . add_statement (parse_quote ! { # left_ident -> [0] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Difference (..) | HfPlusNode :: AntiJoin (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Difference (..)) { parse_quote ! (difference_multiset) } else { parse_quote ! (anti_join_multiset) } ; let (HfPlusNode :: Difference (left , right) | HfPlusNode :: AntiJoin (left , right)) = self else { unreachable ! () } ; let (right , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "difference / anti join inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; if right_was_persist { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } else { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } builder . add_statement (parse_quote ! { # left_ident -> [pos] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [neg] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Map { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let map_id = * next_stmt_id ; * next_stmt_id += 1 ; let map_ident = syn :: Ident :: new (& format ! ("stream_{}" , map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # map_ident = # input_ident -> map (# f) ; }) ; (map_ident , input_location_id) } HfPlusNode :: FlatMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let flat_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let flat_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , flat_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # flat_map_ident = # input_ident -> flat_map (# f) ; }) ; (flat_map_ident , input_location_id) } HfPlusNode :: Filter { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_ident = # input_ident -> filter (# f) ; }) ; (filter_ident , input_location_id) } HfPlusNode :: FilterMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_map_ident = # input_ident -> filter_map (# f) ; }) ; (filter_map_ident , input_location_id) } HfPlusNode :: Sort (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sort_id = * next_stmt_id ; * next_stmt_id += 1 ; let sort_ident = syn :: Ident :: new (& format ! ("stream_{}" , sort_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # sort_ident = # input_ident -> sort () ; }) ; (sort_ident , input_location_id) } HfPlusNode :: DeferTick (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let defer_tick_id = * next_stmt_id ; * next_stmt_id += 1 ; let defer_tick_ident = syn :: Ident :: new (& format ! ("stream_{}" , defer_tick_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # defer_tick_ident = # input_ident -> defer_tick_lazy () ; }) ; (defer_tick_ident , input_location_id) } HfPlusNode :: Enumerate (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let enumerate_id = * next_stmt_id ; * next_stmt_id += 1 ; let enumerate_ident = syn :: Ident :: new (& format ! ("stream_{}" , enumerate_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # enumerate_ident = # input_ident -> enumerate () ; }) ; (enumerate_ident , input_location_id) } HfPlusNode :: Inspect { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let inspect_id = * next_stmt_id ; * next_stmt_id += 1 ; let inspect_ident = syn :: Ident :: new (& format ! ("stream_{}" , inspect_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # inspect_ident = # input_ident -> inspect (# f) ; }) ; (inspect_ident , input_location_id) } HfPlusNode :: Unique (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let unique_id = * next_stmt_id ; * next_stmt_id += 1 ; let unique_ident = syn :: Ident :: new (& format ! ("stream_{}" , unique_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # unique_ident = # input_ident -> unique ::<'tick > () ; }) ; (unique_ident , input_location_id) } HfPlusNode :: Fold { .. } | HfPlusNode :: FoldKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Fold { .. }) { parse_quote ! (fold) } else { parse_quote ! (fold_keyed) } ; let (HfPlusNode :: Fold { init , acc , input } | HfPlusNode :: FoldKeyed { init , acc , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let fold_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'static > (# init , # acc) ; }) ; } else { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'tick > (# init , # acc) ; }) ; } (fold_ident , input_location_id) } HfPlusNode :: Reduce { .. } | HfPlusNode :: ReduceKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Reduce { .. }) { parse_quote ! (reduce) } else { parse_quote ! (reduce_keyed) } ; let (HfPlusNode :: Reduce { f , input } | HfPlusNode :: ReduceKeyed { f , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let reduce_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'static > (# f) ; }) ; } else { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'tick > (# f) ; }) ; } (reduce_ident , input_location_id) } HfPlusNode :: Network { from_location : _ , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input , } => { let (sink_expr , source_expr , _connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { panic ! ("Expected the network to be finalized") } DebugInstantiate :: Finalized (sink , source , connect_fn) => { (sink , source , connect_fn) } } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sender_builder = graph_builders . entry (input_location_id) . or_default () ; if let Some (serialize_pipeline) = serialize_pipeline { sender_builder . add_statement (parse_quote ! { # input_ident -> # serialize_pipeline -> dest_sink (# sink_expr) ; }) ; } else { sender_builder . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink_expr) ; }) ; } let to_id = match to_location { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let receiver_builder = graph_builders . entry (* to_id) . or_default () ; let receiver_stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let receiver_stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , receiver_stream_id) , Span :: call_site ()) ; if let Some (deserialize_pipeline) = deserialize_pipeline { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) -> # deserialize_pipeline ; }) ; } else { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) ; }) ; } (receiver_stream_ident , * to_id) } } } } } pub mod persist_pullup { pub use std :: cell :: RefCell ; pub use std :: collections :: HashSet ; pub use std :: ops :: Deref ; pub use crate :: ir :: * ; pub fn persist_pullup_node < 'a > (node : & mut HfPlusNode < 'a > , seen_tees : & mut SeenTees < 'a > , persist_pulled_tees : & mut HashSet < * const RefCell < HfPlusNode < 'a > > > ,) { node . transform_children (| n , s | persist_pullup_node (n , s , persist_pulled_tees) , seen_tees ,) ; match node { HfPlusNode :: Unpersist (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Unpersist (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Delta (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Delta (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Tee { inner } => { if persist_pulled_tees . contains (& (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >)) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } else { let inner_borrow = inner . borrow () ; if let HfPlusNode :: Persist (_) = inner_borrow . deref () { drop (inner_borrow) ; persist_pulled_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >) ; if let HfPlusNode :: Persist (box behind_persist) = inner . replace (HfPlusNode :: Placeholder) { * inner . borrow_mut () = behind_persist ; } else { unreachable ! () } * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } } } HfPlusNode :: Map { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Map { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Map { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: FlatMap { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: FlatMap { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: FlatMap { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Filter { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Filter { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Filter { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Network { input : box HfPlusNode :: Persist (_) , .. } => { if let HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Union (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Union (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Union (left , right))) ; } else { unreachable ! () } } HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: CrossProduct (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,) ,)))) ; } else { unreachable ! () } } HfPlusNode :: Join (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Join (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: Join (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,))))) ; } else { unreachable ! () } } _ => { } } } pub fn persist_pullup (ir : Vec < HfPlusLeaf >) -> Vec < HfPlusLeaf > { let mut seen_tees = Default :: default () ; let mut persist_pulled_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| n , s | persist_pullup_node (n , s , & mut persist_pulled_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn persist_pullup_through_map () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } # [test] fn persist_pullup_behind_tee () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; let before_tee = flow . source_iter (& process , q ! (0 .. 10)) . tick_batch () . persist () ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } } } pub mod profiler { pub use std :: cell :: RefCell ; pub use hydroflow :: futures :: channel :: mpsc :: UnboundedSender ; pub use stageleft :: * ; pub use crate as hydroflow_plus ; pub use crate :: ir :: * ; pub use crate :: RuntimeContext ; pub fn increment_counter (count : & mut u64) { * count += 1 ; } pub fn quoted_any_fn < 'a , F : Fn (& usize) + 'a , Q : IntoQuotedMut < 'a , F > > (q : Q) -> Q { q } # [doc = " Add a profiling node before each node to count the cardinality of its input"] pub fn add_profiling_node < 'a > (node : & mut HfPlusNode < 'a > , _context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > , id : & mut u32 , seen_tees : & mut SeenTees < 'a > ,) { let my_id = * id ; * id += 1 ; node . transform_children (| node , seen_tees | { add_profiling_node (node , _context , counters , counter_queue , id , seen_tees) } , seen_tees ,) ; let orig_node = std :: mem :: replace (node , HfPlusNode :: Placeholder) ; * node = HfPlusNode :: Inspect { f : quoted_any_fn (q ! ({ counter_queue . borrow () . unbounded_send ((my_id as usize , counters . borrow () [my_id as usize])) . unwrap () ; counters . borrow_mut () [my_id as usize] = 0 ; move | _ | { hydroflow_plus :: profiler :: increment_counter (& mut counters . borrow_mut () [my_id as usize] ,) ; } })) . splice () . into () , input : Box :: new (orig_node) , } } # [doc = " Count the cardinality of each input and periodically output to a file"] pub fn profiling < 'a > (ir : Vec < HfPlusLeaf < 'a > > , context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > ,) -> Vec < HfPlusLeaf < 'a > > { let mut id = 0 ; let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | { add_profiling_node (node , context , counters , counter_queue , & mut id , seen_tees) } , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn profiler_wrapping_all_operators () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let runtime_context = flow . runtime_context () ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (& built . ir ()) ; let counters = RuntimeData :: new ("Fake") ; let counter_queue = RuntimeData :: new ("Fake") ; let pushed_down = built . with_default_optimize () . optimize_with (| ir | super :: profiling (ir , runtime_context , counters , counter_queue)) ; insta :: assert_debug_snapshot ! (& pushed_down . ir ()) ; let _ = pushed_down . compile_no_network :: < MultiGraph > () ; } } } pub mod properties { pub use std :: collections :: HashSet ; pub use stageleft :: * ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , SeenTees } ; pub use crate :: properties :: PropertyDatabase ; # [doc = " Allows us to convert the hydroflow datatype for folds to a binary operation for the algebra"] # [doc = " property tests."] # [allow (dead_code)] pub fn convert_hf_to_binary < I , A : Default , F : Fn (& mut A , I) > (f : F) -> impl Fn (I , I) -> A { move | a , b | { let mut acc = Default :: default () ; f (& mut acc , a) ; f (& mut acc , b) ; acc } } # [cfg (stageleft_macro)] impl PropertyDatabase { # [doc = " Tags the expression as commutative."] pub fn add_commutative_tag < 'a , I , A , F : Fn (& mut A , I) , Q : Quoted < 'a , F > + Clone > (& mut self , expr : Q ,) -> Q { let expr_clone = expr . clone () ; self . commutative . insert (expr_clone . splice ()) ; expr } pub fn is_tagged_commutative (& self , expr : & syn :: Expr) -> bool { self . commutative . contains (expr) } } pub fn properties_optimize_node < 'a > (node : & mut HfPlusNode < 'a > , db : & PropertyDatabase , seen_tees : & mut SeenTees < 'a > ,) { node . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , seen_tees ,) ; match node { HfPlusNode :: ReduceKeyed { f , .. } if db . is_tagged_commutative (& f . 0) => { dbg ! ("IDENTIFIED COMMUTATIVE OPTIMIZATION for {:?}" , & f) ; } _ => { } } } pub fn properties_optimize < 'a > (ir : Vec < HfPlusLeaf < 'a > > , db : & PropertyDatabase ,) -> Vec < HfPlusLeaf < 'a > > { let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use super :: * ; use crate :: deploy :: SingleProcessGraph ; use crate :: FlowBuilder ; # [test] fn test_property_database () { let mut db = PropertyDatabase :: default () ; assert ! (! db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; let _ = db . add_commutative_tag (q ! (| a : & mut i32 , b : i32 | * a += b)) ; assert ! (db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; } # [test] fn test_property_optimized () { let flow = FlowBuilder :: new () ; let mut database = PropertyDatabase :: default () ; let process = flow . process :: < () > () ; let counter_func = q ! (| count : & mut i32 , _ | * count += 1) ; let _ = database . add_commutative_tag (counter_func) ; flow . source_iter (& process , q ! (vec ! [])) . map (q ! (| string : String | (string , ()))) . tick_batch () . fold_keyed (q ! (|| 0) , counter_func) . all_ticks () . for_each (q ! (| (string , count) | println ! ("{}: {}" , string , count))) ; let built = flow . finalize () . optimize_with (| ir | properties_optimize (ir , & database)) . with_default_optimize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let _ = built . compile_no_network :: < SingleProcessGraph > () ; } } } pub use crate :: RuntimeContext ; # [cfg (stageleft_macro)] impl Copy for RuntimeContext < '_ > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Context > for RuntimeContext < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (quote ! (& context))) } } pub use crate :: HfCompiled ; # [cfg (stageleft_macro)] impl < 'a , ID > HfCompiled < 'a , ID > { pub fn hydroflow_ir (& self) -> & BTreeMap < usize , HydroflowGraph > { & self . hydroflow_ir } } # [cfg (stageleft_macro)] impl < 'a > HfCompiled < 'a , usize > { pub fn with_dynamic_id (self , id : impl Quoted < 'a , usize >) -> HfBuiltWithId < 'a > { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; let mut conditioned_tokens = None ; for (subgraph_id , flat_graph) in self . hydroflow_ir { let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; let my_extra_stmts = self . extra_stmts . get (& subgraph_id) . cloned () . unwrap_or_default () ; if let Some (conditioned_tokens) = conditioned_tokens . as_mut () { * conditioned_tokens = syn :: parse_quote ! { # conditioned_tokens else if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } } ; } else { conditioned_tokens = Some (syn :: parse_quote ! { if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } }) ; } } let conditioned_tokens : TokenStream = conditioned_tokens . unwrap () ; let id = id . splice () ; HfBuiltWithId { tokens : syn :: parse_quote ! ({ let __given_id = # id ; # conditioned_tokens else { panic ! ("Invalid node id: {}" , __given_id) ; } }) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfCompiled < 'a , () > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfCompiled < 'a , () > { fn to_tokens (mut self) -> (Option < TokenStream > , Option < TokenStream >) { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; if self . hydroflow_ir . len () != 1 { panic ! ("Expected exactly one subgraph in the Hydroflow IR") ; } let flat_graph = self . hydroflow_ir . remove (& 0) . unwrap () ; let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; (None , Some (tokens)) } } pub use crate :: HfBuiltWithId ; # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfBuiltWithId < 'a > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfBuiltWithId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (self . tokens)) } }
[INFO] [stdout] 1 + pub use std :: collections :: BTreeMap ; pub use std :: marker :: PhantomData ; pub use hydroflow :: scheduled :: context :: Context ; pub use hydroflow :: scheduled :: graph :: Hydroflow ; pub use hydroflow :: * ; pub use lang :: graph :: { partition_graph , HydroflowGraph } ; pub use proc_macro2 :: TokenStream ; pub use quote :: quote ; pub use stageleft :: runtime_support :: FreeVariable ; pub use stageleft :: Quoted ; pub mod runtime_support { pub use bincode ; } pub mod stream { pub use std :: cell :: RefCell ; pub use std :: hash :: Hash ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow :: bytes :: Bytes ; pub use hydroflow :: futures :: Sink ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: quote ; pub use serde :: de :: DeserializeOwned ; pub use serde :: Serialize ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use syn :: parse_quote ; pub use crate :: builder :: { ClusterIds , FlowLeaves } ; pub use crate :: cycle :: { CycleCollection , CycleComplete } ; pub use crate :: ir :: { DebugInstantiate , HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { CanSend , Location , LocationId } ; pub use crate :: { Cluster , Optional , Singleton } ; pub use crate :: stream :: Unbounded ; pub use crate :: stream :: Bounded ; pub use crate :: stream :: NoTick ; pub use crate :: stream :: Tick ; pub use crate :: stream :: Stream ; # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Stream { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Stream < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Stream { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , C , N > > ,) -> Stream < 'a , (T , O) , W , C , N > where O : Clone , { let other : Optional < 'a , O , Bounded , C , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn cross_product < O > (self , other : Stream < 'a , O , W , C , N >) -> Stream < 'a , (T , O) , W , C , N > where T : Clone , O : Clone , { if self . location_kind != other . location_kind { panic ! ("cross_product must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossProduct (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn union (self , other : Stream < 'a , T , W , C , N >) -> Stream < 'a , T , W , C , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn dest_sink < S : Unpin + Sink < T > + 'a > (self , sink : impl Quoted < 'a , S >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: DestSink { sink : sink . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn first (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } # [doc = " Allow this stream through if the other stream has elements, otherwise the output is empty."] pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } # [doc = " Allow this stream through if the other stream is empty, otherwise the output is empty."] pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn enumerate (self) -> Stream < 'a , (usize , T) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Enumerate (Box :: new (self . ir_node . into_inner ())) ,) } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn sort (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Ord , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Sort (Box :: new (self . ir_node . into_inner ())) ,) } pub fn count (self) -> Singleton < 'a , usize , Bounded , Tick , N > { self . fold (q ! (|| 0usize) , q ! (| count , _ | * count += 1)) } pub fn delta (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } pub fn unique (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Eq + Hash , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unique (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn tick_batch (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_prefix (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { self . tick_batch () . persist () } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn for_each < F : Fn (T) + 'a > (self , f : impl IntoQuotedMut < 'a , F >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: ForEach { input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , f : f . splice () . into () , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Unbounded , NoTick , N > { pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . tick_batch () . continue_if (samples . first ()) . all_ticks () } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Unbounded , NoTick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , C , N : Location > Stream < 'a , T , Bounded , C , N > { pub fn filter_not_in (self , other : Stream < 'a , T , Bounded , C , N >) -> Stream < 'a , T , Bounded , C , N > where T : Eq + Hash , { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Difference (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Stream < 'a , & T , W , C , N > { pub fn cloned (self) -> Stream < 'a , T , W , C , N > { self . map (q ! (| d | d . clone ())) } } # [cfg (stageleft_macro)] impl < 'a , K , V1 , W , C , N : Location > Stream < 'a , (K , V1) , W , C , N > { pub fn join < W2 , V2 > (self , n : Stream < 'a , (K , V2) , W2 , C , N > ,) -> Stream < 'a , (K , (V1 , V2)) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Join (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } pub fn anti_join < W2 > (self , n : Stream < 'a , K , W2 , C , N >) -> Stream < 'a , (K , V1) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("anti_join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: AntiJoin (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , K : Eq + Hash , V , N : Location > Stream < 'a , (K , V) , Bounded , Tick , N > { pub fn fold_keyed < A , I : Fn () -> A + 'a , F : Fn (& mut A , V) + 'a > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , A) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FoldKeyed { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce_keyed < F : Fn (& mut V , V) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , V) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: ReduceKeyed { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } pub fn get_this_crate () -> TokenStream { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , Span :: call_site ()) ; quote ! { # ident } } } } pub fn serialize_bincode < T : Serialize > (is_demux : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if is_demux { parse_quote ! { map (| (id , data) | { (id , # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into ()) }) } } else { parse_quote ! { map (| data | { # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into () }) } } } pub fn deserialize_bincode < T : DeserializeOwned > (tagged : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if tagged { parse_quote ! { map (| res | { let (id , b) = res . unwrap () ; (id , # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& b) . unwrap ()) }) } } else { parse_quote ! { map (| res | { # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& res . unwrap ()) . unwrap () }) } } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn send_bincode < N2 : Location , CoreType > (self , other : & N2 ,) -> Stream < 'a , N :: Out < CoreType > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T > , CoreType : Serialize + DeserializeOwned , { let serialize_pipeline = Some (serialize_bincode :: < CoreType > (N :: is_demux ())) ; let deserialize_pipeline = Some (deserialize_bincode :: < CoreType > (N :: is_tagged ())) ; Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bytes < N2 : Location > (self , other : & N2 ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T > , { Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline : None , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline : if N :: is_tagged () { Some (parse_quote ! (map (| (id , b) | (id , b . unwrap () . freeze ())))) } else { Some (parse_quote ! (map (| b | b . unwrap () . freeze ()))) } , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bincode_interleaved < N2 : Location , Tag , CoreType > (self , other : & N2 ,) -> Stream < 'a , CoreType , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T , Out < CoreType > = (Tag , CoreType) > , CoreType : Serialize + DeserializeOwned , { self . send_bincode :: < N2 , CoreType > (other) . map (q ! (| (_ , b) | b)) } pub fn send_bytes_interleaved < N2 : Location , Tag > (self , other : & N2 ,) -> Stream < 'a , Bytes , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T , Out < Bytes > = (Tag , Bytes) > , { self . send_bytes :: < N2 > (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bincode < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < T > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) > , T : Clone + Serialize + DeserializeOwned , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bincode (other) } pub fn broadcast_bincode_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , T , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) , Out < T > = (Tag , T) > + 'a , T : Clone + Serialize + DeserializeOwned , { self . broadcast_bincode (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bytes < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) > + 'a , T : Clone , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bytes (other) } pub fn broadcast_bytes_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , Bytes , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) , Out < Bytes > = (Tag , Bytes) > + 'a , T : Clone , { self . broadcast_bytes (other) . map (q ! (| (_ , b) | b)) } } } pub use stream :: { Bounded , NoTick , Stream , Tick , Unbounded } ; pub mod singleton { pub use std :: cell :: RefCell ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use crate :: builder :: FlowLeaves ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial , CycleComplete } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: Stream ; pub use crate :: singleton :: CrossResult ; # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Singleton < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Singleton :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } pub use crate :: singleton :: Singleton ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Singleton { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleComplete < 'a > for Singleton < 'a , T , Bounded , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleCollectionWithInitial < 'a > for Singleton < 'a , T , Bounded , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , initial : Self , l : LocationId ,) -> Self { Singleton :: new (l , ir_leaves , HfPlusNode :: Union (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , }) , initial . ir_node . into_inner () . into () ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Singleton < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Singleton { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , U , W , C , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (Self :: other_ir_node (other)) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Singleton < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CrossSingleton (Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , Box :: new (HfPlusNode :: Unpersist (Box :: new (Self :: other_ir_node (other)))) ,))) ,) } } pub use crate :: singleton :: Optional ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Optional { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } pub fn some (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: new (singleton . location_kind , singleton . ir_leaves , singleton . ir_node . into_inner () ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > From < Singleton < 'a , T , W , C , N > > for Optional < 'a , T , W , C , N > { fn from (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: some (singleton) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Optional < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Optional { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn into_stream (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , Tick , N > > ,) -> Optional < 'a , (T , O) , Bounded , Tick , N > where O : Clone , { let other : Optional < 'a , O , Bounded , Tick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn union (self , other : Optional < 'a , T , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Optional < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_samples (self) -> Stream < 'a , T , Unbounded , NoTick , N > { self . latest_tick () . all_ticks () } pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . latest_tick () . continue_if (samples . first ()) . latest () . tick_samples () } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Unbounded , NoTick , N > > ,) -> Optional < 'a , (T , O) , Unbounded , NoTick , N > where O : Clone , { let other : Optional < 'a , O , Unbounded , NoTick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } self . latest_tick () . cross_singleton (other . latest_tick ()) . latest () } } } pub use singleton :: { Optional , Singleton } ; pub mod location { pub use std :: marker :: PhantomData ; pub use crate :: location :: LocationId ; pub use crate :: location :: Location ; pub use crate :: location :: Process ; # [cfg (stageleft_macro)] impl < P > Clone for Process < P > { fn clone (& self) -> Self { Process { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < P > Location for Process < P > { fn id (& self) -> LocationId { LocationId :: Process (self . id) } } pub use crate :: location :: Cluster ; # [cfg (stageleft_macro)] impl < C > Clone for Cluster < C > { fn clone (& self) -> Self { Cluster { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < C > Location for Cluster < C > { fn id (& self) -> LocationId { LocationId :: Cluster (self . id) } } pub use crate :: location :: CanSend ; # [cfg (stageleft_macro)] impl < P1 , P2 > CanSend < Process < P2 > > for Process < P1 > { type In < T > = T ; type Out < T > = T ; fn is_demux () -> bool { false } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < P1 , C2 > CanSend < Cluster < C2 > > for Process < P1 > { type In < T > = (u32 , T) ; type Out < T > = T ; fn is_demux () -> bool { true } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < C1 , P2 > CanSend < Process < P2 > > for Cluster < C1 > { type In < T > = T ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { false } fn is_tagged () -> bool { true } } # [cfg (stageleft_macro)] impl < C1 , C2 > CanSend < Cluster < C2 > > for Cluster < C1 > { type In < T > = (u32 , T) ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { true } fn is_tagged () -> bool { true } } } pub use location :: { Cluster , Process } ; pub mod deploy { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use stageleft :: Quoted ; pub mod graphs { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use super :: { LocalDeploy , Node , ProcessSpec } ; pub use crate :: deploy :: graphs :: SingleProcessGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for SingleProcessGraph { type Process = SingleNode ; type Cluster = SingleNode ; type Meta = () ; type GraphId = () ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { SingleNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { SingleNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , SingleProcessGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> SingleNode { SingleNode { } } } pub use crate :: deploy :: graphs :: SingleNode ; # [cfg (stageleft_macro)] impl Node for SingleNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } pub use crate :: deploy :: graphs :: MultiGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for MultiGraph { type Process = MultiNode ; type Cluster = MultiNode ; type Meta = () ; type GraphId = usize ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { MultiNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { MultiNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , MultiGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> MultiNode { MultiNode { } } } pub use crate :: deploy :: graphs :: MultiNode ; # [cfg (stageleft_macro)] impl Node for MultiNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } } pub use graphs :: * ; pub use crate :: deploy :: LocalDeploy ; pub use crate :: deploy :: Deploy ; # [cfg (stageleft_macro)] impl < 'a , T : Deploy < 'a , Process = N , Cluster = C , Meta = M , GraphId = R > , N : Node < Meta = M > , C : Node < Meta = M > , M : Default , R , > LocalDeploy < 'a > for T { type Process = N ; type Cluster = C ; type Meta = M ; type GraphId = R ; fn has_trivial_node () -> bool { < T as Deploy < 'a > > :: has_trivial_node () } fn trivial_process (id : usize) -> Self :: Process { < T as Deploy < 'a > > :: trivial_process (id) } fn trivial_cluster (id : usize) -> Self :: Cluster { < T as Deploy < 'a > > :: trivail_cluster (id) } } pub use crate :: deploy :: ProcessSpec ; pub use crate :: deploy :: ClusterSpec ; pub use crate :: deploy :: Node ; } pub use deploy :: { ClusterSpec , Deploy , ProcessSpec } ; pub mod cycle { pub use std :: marker :: PhantomData ; pub use crate :: builder :: FlowLeaves ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: cycle :: CycleComplete ; pub use crate :: cycle :: CycleCollection ; pub use crate :: cycle :: CycleCollectionWithInitial ; pub use crate :: cycle :: HfCycle ; # [cfg (stageleft_macro)] impl < 'a , S : CycleComplete < 'a > > HfCycle < 'a , S > { pub fn complete (self , stream : S) { let ident = self . ident ; S :: complete (stream , ident) } } } pub use cycle :: HfCycle ; pub mod builder { pub use std :: cell :: RefCell ; pub use std :: collections :: HashMap ; pub use std :: marker :: PhantomData ; pub use std :: rc :: Rc ; pub use std :: time :: Duration ; pub use hydroflow :: futures :: stream :: Stream as FuturesStream ; pub use hydroflow :: { tokio , tokio_stream } ; pub use internal :: TokenStream ; pub use proc_macro2 :: Span ; pub use quote :: quote ; pub use runtime_support :: FreeVariable ; pub use stageleft :: * ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Cluster , Location , LocationId , Process } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: { HfCycle , Optional , RuntimeContext , Singleton , Stream } ; pub mod built { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use hydroflow_lang :: graph :: { eliminate_extra_unions_tees , HydroflowGraph } ; pub use super :: deploy :: { DeployFlow , DeployResult } ; pub use crate :: deploy :: { ClusterSpec , Deploy , LocalDeploy , ProcessSpec } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Cluster , Process } ; pub use crate :: HfCompiled ; pub use crate :: builder :: built :: BuiltFlow ; # [cfg (stageleft_macro)] impl < 'a > Drop for BuiltFlow < 'a > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped BuiltFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn ir (& self) -> & Vec < HfPlusLeaf < 'a > > { & self . ir } pub fn optimize_with (mut self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> BuiltFlow < 'a > { self . used = true ; BuiltFlow { ir : f (std :: mem :: take (& mut self . ir)) , processes : std :: mem :: take (& mut self . processes) , clusters : std :: mem :: take (& mut self . clusters) , used : false , _phantom : PhantomData , } } } pub fn build_inner (ir : & mut Vec < HfPlusLeaf >) -> BTreeMap < usize , HydroflowGraph > { let mut builders = BTreeMap :: new () ; let mut built_tees = HashMap :: new () ; let mut next_stmt_id = 0 ; for leaf in ir { leaf . emit (& mut builders , & mut built_tees , & mut next_stmt_id) ; } builders . into_iter () . map (| (k , v) | { let (mut flat_graph , _ , _) = v . build () ; eliminate_extra_unions_tees (& mut flat_graph) ; (k , flat_graph) }) . collect () } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn compile_no_network < D : LocalDeploy < 'a > > (mut self) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; HfCompiled { hydroflow_ir : build_inner (& mut self . ir) , extra_stmts : BTreeMap :: new () , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> BuiltFlow < 'a > { self . optimize_with (crate :: persist_pullup :: persist_pullup) } fn into_deploy < D : LocalDeploy < 'a > > (mut self) -> DeployFlow < 'a , D > { self . used = true ; let processes = if D :: has_trivial_node () { self . processes . iter () . map (| id | (* id , D :: trivial_process (* id))) . collect () } else { HashMap :: new () } ; let clusters = if D :: has_trivial_node () { self . clusters . iter () . map (| id | (* id , D :: trivial_cluster (* id))) . collect () } else { HashMap :: new () } ; DeployFlow { ir : std :: mem :: take (& mut self . ir) , nodes : processes , clusters , used : false , _phantom : PhantomData , } } pub fn with_process < P , D : LocalDeploy < 'a > > (self , process : & Process < P > , spec : impl ProcessSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_process (process , spec) } pub fn with_cluster < C , D : LocalDeploy < 'a > > (self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_cluster (cluster , spec) } pub fn compile < D : Deploy < 'a > + 'a > (self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . into_deploy :: < D > () . compile (env) } pub fn deploy < D : Deploy < 'a , CompileEnv = () > + 'a > (self , env : & mut D :: InstantiateEnv ,) -> DeployResult < 'a , D > { self . into_deploy :: < D > () . deploy (env) } } } pub mod deploy { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use proc_macro2 :: Span ; pub use stageleft :: Quoted ; pub use super :: built :: build_inner ; pub use crate :: deploy :: { LocalDeploy , Node } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: { Cluster , ClusterSpec , Deploy , HfCompiled , Process , ProcessSpec } ; pub use crate :: builder :: deploy :: DeployFlow ; # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > Drop for DeployFlow < 'a , D > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped DeployFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > DeployFlow < 'a , D > { pub fn with_process < P > (mut self , process : & Process < P > , spec : impl ProcessSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < P > () . to_string () ; self . nodes . insert (process . id , spec . build (process . id , & tag_name)) ; self } pub fn with_cluster < C > (mut self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < C > () . to_string () ; self . clusters . insert (cluster . id , spec . build (cluster . id , & tag_name)) ; self } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployFlow < 'a , D > { pub fn compile (mut self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; let mut seen_tees : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | leaf . compile_network :: < D > (env , & mut seen_tees , & self . nodes , & self . clusters)) . collect () ; let extra_stmts = self . extra_stmts (env) ; HfCompiled { hydroflow_ir : build_inner (& mut ir_leaves_networked) , extra_stmts , _phantom : PhantomData , } } fn extra_stmts (& self , env : & < D as Deploy < 'a > > :: CompileEnv) -> BTreeMap < usize , Vec < syn :: Stmt > > { let all_locations_count = self . nodes . len () + self . clusters . len () ; let mut extra_stmts : BTreeMap < usize , Vec < syn :: Stmt > > = BTreeMap :: new () ; for & c_id in self . clusters . keys () { let self_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , c_id) , Span :: call_site () ,) ; let self_id_expr = D :: cluster_self_id (env) . splice () ; extra_stmts . entry (c_id) . or_default () . push (syn :: parse_quote ! { let # self_id_ident = # self_id_expr ; }) ; for other_location in 0 .. all_locations_count { let other_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , c_id) , Span :: call_site () ,) ; let other_id_expr = D :: cluster_ids (env , c_id) . splice () ; extra_stmts . entry (other_location) . or_default () . push (syn :: parse_quote ! { let # other_id_ident = # other_id_expr ; }) ; } } extra_stmts } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a , CompileEnv = () > > DeployFlow < 'a , D > { # [must_use] pub fn deploy (mut self , env : & mut D :: InstantiateEnv) -> DeployResult < 'a , D > { self . used = true ; let mut seen_tees_instantiate : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | { leaf . compile_network :: < D > (& () , & mut seen_tees_instantiate , & self . nodes , & self . clusters ,) }) . collect () ; let mut compiled = build_inner (& mut ir_leaves_networked) ; let mut extra_stmts = self . extra_stmts (& ()) ; let mut meta = D :: Meta :: default () ; let (mut processes , mut clusters) = (std :: mem :: take (& mut self . nodes) . into_iter () . map (| (node_id , node) | { node . instantiate (env , & mut meta , compiled . remove (& node_id) . unwrap () , extra_stmts . remove (& node_id) . unwrap_or_default () ,) ; (node_id , node) }) . collect :: < HashMap < _ , _ > > () , std :: mem :: take (& mut self . clusters) . into_iter () . map (| (cluster_id , cluster) | { cluster . instantiate (env , & mut meta , compiled . remove (& cluster_id) . unwrap () , extra_stmts . remove (& cluster_id) . unwrap_or_default () ,) ; (cluster_id , cluster) }) . collect :: < HashMap < _ , _ > > () ,) ; for node in processes . values_mut () { node . update_meta (& meta) ; } for cluster in clusters . values_mut () { cluster . update_meta (& meta) ; } let mut seen_tees_connect = HashMap :: new () ; for leaf in ir_leaves_networked { leaf . connect_network (& mut seen_tees_connect) ; } DeployResult { processes , clusters , } } } pub use crate :: builder :: deploy :: DeployResult ; # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployResult < 'a , D > { pub fn get_process < P > (& self , p : & Process < P >) -> & D :: Process { let id = match p . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . processes . get (& id) . unwrap () } pub fn get_cluster < C > (& self , c : & Cluster < C >) -> & D :: Cluster { let id = match c . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . clusters . get (& id) . unwrap () } } } # [doc = " Tracks the leaves of the dataflow IR. This is referenced by"] # [doc = " `Stream` and `HfCycle` to build the IR. The inner option will"] # [doc = " be set to `None` when this builder is finalized."] pub type FlowLeaves < 'a > = Rc < RefCell < Option < Vec < HfPlusLeaf < 'a > > > > > ; pub use crate :: builder :: ClusterIds ; # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Vec < u32 > > for ClusterIds < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , & 'a Vec < u32 > > for ClusterIds < 'a > { } # [derive (Copy , Clone)] pub struct ClusterSelfId < 'a > { pub id : usize , pub _phantom : PhantomData < & 'a mut & 'a u32 > , } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < u32 > for ClusterSelfId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , u32 > for ClusterSelfId < 'a > { } pub use crate :: builder :: FlowBuilder ; # [cfg (stageleft_macro)] impl < 'a > Drop for FlowBuilder < 'a > { fn drop (& mut self) { if ! self . finalized { panic ! ("Dropped FlowBuilder without finalizing, you may have forgotten to call `with_default_optimize`, `optimize_with`, or `finalize`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > QuotedContext for FlowBuilder < 'a > { fn create () -> Self { FlowBuilder :: new () } } # [cfg (stageleft_macro)] impl < 'a > FlowBuilder < 'a > { # [allow (clippy :: new_without_default)] pub fn new () -> FlowBuilder < 'a > { FlowBuilder { ir_leaves : Rc :: new (RefCell :: new (Some (Vec :: new ()))) , nodes : RefCell :: new (vec ! []) , clusters : RefCell :: new (vec ! []) , cycle_ids : RefCell :: new (HashMap :: new ()) , next_node_id : RefCell :: new (0) , finalized : false , _phantom : PhantomData , } } pub fn finalize (mut self) -> built :: BuiltFlow < 'a > { self . finalized = true ; built :: BuiltFlow { ir : self . ir_leaves . borrow_mut () . take () . unwrap () , processes : self . nodes . replace (vec ! []) , clusters : self . clusters . replace (vec ! []) , used : false , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> built :: BuiltFlow < 'a > { self . finalize () . with_default_optimize () } pub fn optimize_with (self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> built :: BuiltFlow < 'a > { self . finalize () . optimize_with (f) } pub fn ir_leaves (& self) -> & FlowLeaves < 'a > { & self . ir_leaves } pub fn process < P > (& self) -> Process < P > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . nodes . borrow_mut () . push (id) ; Process { id , _phantom : PhantomData , } } pub fn cluster < C > (& self) -> Cluster < C > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . clusters . borrow_mut () . push (id) ; Cluster { id , _phantom : PhantomData , } } pub fn runtime_context (& self) -> RuntimeContext < 'a > { RuntimeContext { _phantom : PhantomData , } } pub fn cluster_members < C > (& self , cluster : & Cluster < C > ,) -> impl Quoted < 'a , & 'a Vec < u32 > > + Copy + 'a { ClusterIds { id : cluster . id , _phantom : PhantomData , } } pub fn cluster_self_id < C > (& self , cluster : & Cluster < C >) -> impl Quoted < 'a , u32 > + Copy + 'a { ClusterSelfId { id : cluster . id , _phantom : PhantomData , } } pub fn spin < L : Location > (& self , on : & L) -> Stream < 'a , () , Unbounded , NoTick , L > { Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Spin () , location_kind : on . id () , })) ,) } pub fn spin_batch < L : Location > (& self , on : & L , batch_size : impl Quoted < 'a , usize > + Copy + 'a ,) -> Stream < 'a , () , Bounded , Tick , L > { self . spin (on) . flat_map (q ! (move | _ | 0 .. batch_size)) . map (q ! (| _ | ())) . tick_batch () } pub fn source_stream < T , E : FuturesStream < Item = T > + Unpin , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Unbounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Stream (e . into ()) , location_kind : on . id () , })) ,) } pub fn source_iter < T , E : IntoIterator < Item = T > , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Bounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , })) ,) } pub fn singleton < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Singleton < 'a , T , Bounded , NoTick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Singleton :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,)))) ,) } pub fn singleton_first_tick < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Optional < 'a , T , Bounded , Tick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,) } pub fn source_interval < L : Location > (& self , on : & L , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , () , Unbounded , NoTick , L > { let interval = interval . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : on . id () , })) ,) } pub fn source_interval_delayed < L : Location > (& self , on : & L , delay : impl Quoted < 'a , Duration > + Copy + 'a , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , tokio :: time :: Instant , Unbounded , NoTick , L > { self . source_stream (on , q ! (tokio_stream :: wrappers :: IntervalStream :: new (tokio :: time :: interval_at (tokio :: time :: Instant :: now () + delay , interval))) ,) . tick_batch () . first () . latest () } pub fn cycle < S : CycleCollection < 'a > > (& self , on : & S :: Location) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , on . id ()) ,) } pub fn cycle_with_initial < S : CycleCollectionWithInitial < 'a > > (& self , on : & S :: Location , initial : S ,) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , initial , on . id ()) ,) } } } pub use builder :: FlowBuilder ; pub mod ir { pub use core :: panic ; pub use std :: cell :: RefCell ; pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow_lang :: graph :: FlatGraphBuilder ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: ToTokens ; pub use syn :: parse_quote ; pub use crate :: deploy :: Deploy ; pub use crate :: location :: LocationId ; pub use crate :: ir :: DebugExpr ; # [cfg (stageleft_macro)] impl From < syn :: Expr > for DebugExpr { fn from (expr : syn :: Expr) -> DebugExpr { DebugExpr (expr) } } # [cfg (stageleft_macro)] impl Deref for DebugExpr { type Target = syn :: Expr ; fn deref (& self) -> & Self :: Target { & self . 0 } } # [cfg (stageleft_macro)] impl ToTokens for DebugExpr { fn to_tokens (& self , tokens : & mut TokenStream) { self . 0 . to_tokens (tokens) ; } } # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugExpr { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "{}" , self . 0 . to_token_stream ()) } } pub use crate :: ir :: DebugInstantiate ; # [cfg (stageleft_macro)] impl < 'a > std :: fmt :: Debug for DebugInstantiate < 'a > { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<network instantiate>") } } pub use crate :: ir :: DebugPipelineFn ; # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugPipelineFn { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<function>") } } pub use crate :: ir :: HfPlusSource ; pub use crate :: ir :: HfPlusLeaf ; # [cfg (stageleft_macro)] impl < 'a > HfPlusLeaf < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . compile_network :: < D > (compile_env , s , nodes , clusters) ; } , seen_tees ,) } pub fn connect_network (self , seen_tees : & mut SeenTees < 'a >) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . connect_network (s) ; } , seen_tees ,) } pub fn transform_children (self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) -> HfPlusLeaf < 'a > { match self { HfPlusLeaf :: ForEach { f , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: ForEach { f , input } } HfPlusLeaf :: DestSink { sink , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: DestSink { sink , input } } HfPlusLeaf :: CycleSink { ident , location_kind , mut input , } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: CycleSink { ident , location_kind , input , } } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) { match self { HfPlusLeaf :: ForEach { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> for_each (# f) ; }) ; } HfPlusLeaf :: DestSink { sink , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink) ; }) ; } HfPlusLeaf :: CycleSink { ident , location_kind , input , } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; assert_eq ! (input_location_id , * location_id , "cycle_sink location mismatch") ; graph_builders . entry (* location_id) . or_default () . add_statement (parse_quote ! { # ident = # input_ident ; }) ; } } } } pub use crate :: ir :: HfPlusNode ; pub type SeenTees < 'a > = HashMap < * const RefCell < HfPlusNode < 'a > > , Rc < RefCell < HfPlusNode < 'a > > > > ; # [cfg (stageleft_macro)] impl < 'a > HfPlusNode < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (& mut self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) { self . transform_children (| n , s | n . compile_network :: < D > (compile_env , s , nodes , clusters) , seen_tees ,) ; if let HfPlusNode :: Network { from_location , to_location , instantiate_fn , .. } = self { let (sink_expr , source_expr , connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { let ((sink , source) , connect_fn) = match (from_location , to_location) { (LocationId :: Process (from) , LocationId :: Process (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: o2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Process (from) , LocationId :: Cluster (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: o2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Process (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: m2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Cluster (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: m2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } } ; (sink , source , connect_fn) } DebugInstantiate :: Finalized (_ , _ , _) => panic ! ("network already finalized") , } ; * instantiate_fn = DebugInstantiate :: Finalized (sink_expr , source_expr , connect_fn) ; } } pub fn connect_network (& mut self , seen_tees : & mut SeenTees < 'a >) { self . transform_children (| n , s | n . connect_network (s) , seen_tees) ; if let HfPlusNode :: Network { instantiate_fn , .. } = self { match instantiate_fn { DebugInstantiate :: Building () => panic ! ("network not built") , DebugInstantiate :: Finalized (_ , _ , ref connect_fn) => { connect_fn () ; } } } } pub fn transform_children (& mut self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) { match self { HfPlusNode :: Placeholder => { panic ! () ; } HfPlusNode :: Source { .. } => { } HfPlusNode :: CycleSource { .. } => { } HfPlusNode :: Tee { inner } => { if let Some (transformed) = seen_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { * inner = transformed . clone () ; } else { let transformed_cell = Rc :: new (RefCell :: new (HfPlusNode :: Placeholder)) ; seen_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , transformed_cell . clone () ,) ; let mut orig = inner . replace (HfPlusNode :: Placeholder) ; transform (& mut orig , seen_tees) ; * transformed_cell . borrow_mut () = orig ; * inner = transformed_cell ; } } HfPlusNode :: Persist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Unpersist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Delta (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Union (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossProduct (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossSingleton (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Join (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Difference (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: AntiJoin (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Map { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FlatMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Filter { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FilterMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Sort (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: DeferTick (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Enumerate (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Inspect { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Unique (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Fold { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FoldKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Reduce { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: ReduceKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Network { input , .. } => { transform (input . as_mut () , seen_tees) ; } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) -> (syn :: Ident , usize) { match self { HfPlusNode :: Placeholder => { panic ! () } HfPlusNode :: Persist (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let persist_id = * next_stmt_id ; * next_stmt_id += 1 ; let persist_ident = syn :: Ident :: new (& format ! ("stream_{}" , persist_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # persist_ident = # inner_ident -> persist ::<'static > () ; }) ; (persist_ident , location) } HfPlusNode :: Unpersist (_) => { panic ! ("Unpersist is a marker node and should have been optimized away. This is likely a compiler bug.") } HfPlusNode :: Delta (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let delta_id = * next_stmt_id ; * next_stmt_id += 1 ; let delta_ident = syn :: Ident :: new (& format ! ("stream_{}" , delta_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # delta_ident = # inner_ident -> multiset_delta () ; }) ; (delta_ident , location) } HfPlusNode :: Source { source , location_kind , } => { let source_id = * next_stmt_id ; * next_stmt_id += 1 ; let source_ident = syn :: Ident :: new (& format ! ("stream_{}" , source_id) , Span :: call_site ()) ; let source_stmt = match source { HfPlusSource :: Stream (expr) => { parse_quote ! { # source_ident = source_stream (# expr) ; } } HfPlusSource :: Iter (expr) => { parse_quote ! { # source_ident = source_iter (# expr) ; } } HfPlusSource :: Interval (expr) => { parse_quote ! { # source_ident = source_interval (# expr) ; } } HfPlusSource :: Spin () => { parse_quote ! { # source_ident = spin () ; } } } ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; graph_builders . entry (* location_id) . or_default () . add_statement (source_stmt) ; (source_ident , * location_id) } HfPlusNode :: CycleSource { ident , location_kind , } => { let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; (ident . clone () , * location_id) } HfPlusNode :: Tee { inner } => { if let Some (ret) = built_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { ret . clone () } else { let (inner_ident , inner_location_id) = inner . borrow () . emit (graph_builders , built_tees , next_stmt_id) ; let tee_id = * next_stmt_id ; * next_stmt_id += 1 ; let tee_ident = syn :: Ident :: new (& format ! ("stream_{}" , tee_id) , Span :: call_site ()) ; let builder = graph_builders . entry (inner_location_id) . or_default () ; builder . add_statement (parse_quote ! { # tee_ident = # inner_ident -> tee () ; }) ; built_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , (tee_ident . clone () , inner_location_id) ,) ; (tee_ident , inner_location_id) } } HfPlusNode :: Union (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "union inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let union_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # union_ident = union () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [0] # union_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # union_ident ; }) ; (union_ident , left_location_id) } HfPlusNode :: CrossSingleton (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "cross_singleton inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let cross_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # cross_ident = cross_singleton () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [input] # cross_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [single] # cross_ident ; }) ; (cross_ident , left_location_id) } HfPlusNode :: CrossProduct (..) | HfPlusNode :: Join (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: CrossProduct (..)) { parse_quote ! (cross_join_multiset) } else { parse_quote ! (join_multiset) } ; let (HfPlusNode :: CrossProduct (left , right) | HfPlusNode :: Join (left , right)) = self else { unreachable ! () } ; let (left_inner , left_was_persist) = if let HfPlusNode :: Persist (left) = left . as_ref () { (left , true) } else { (left , false) } ; let (right_inner , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left_inner . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right_inner . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "join / cross product inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; match (left_was_persist , right_was_persist) { (true , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'static > () ; }) ; } (true , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'tick > () ; }) ; } (false , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } (false , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } } ; builder . add_statement (parse_quote ! { # left_ident -> [0] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Difference (..) | HfPlusNode :: AntiJoin (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Difference (..)) { parse_quote ! (difference_multiset) } else { parse_quote ! (anti_join_multiset) } ; let (HfPlusNode :: Difference (left , right) | HfPlusNode :: AntiJoin (left , right)) = self else { unreachable ! () } ; let (right , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "difference / anti join inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; if right_was_persist { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } else { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } builder . add_statement (parse_quote ! { # left_ident -> [pos] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [neg] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Map { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let map_id = * next_stmt_id ; * next_stmt_id += 1 ; let map_ident = syn :: Ident :: new (& format ! ("stream_{}" , map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # map_ident = # input_ident -> map (# f) ; }) ; (map_ident , input_location_id) } HfPlusNode :: FlatMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let flat_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let flat_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , flat_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # flat_map_ident = # input_ident -> flat_map (# f) ; }) ; (flat_map_ident , input_location_id) } HfPlusNode :: Filter { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_ident = # input_ident -> filter (# f) ; }) ; (filter_ident , input_location_id) } HfPlusNode :: FilterMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_map_ident = # input_ident -> filter_map (# f) ; }) ; (filter_map_ident , input_location_id) } HfPlusNode :: Sort (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sort_id = * next_stmt_id ; * next_stmt_id += 1 ; let sort_ident = syn :: Ident :: new (& format ! ("stream_{}" , sort_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # sort_ident = # input_ident -> sort () ; }) ; (sort_ident , input_location_id) } HfPlusNode :: DeferTick (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let defer_tick_id = * next_stmt_id ; * next_stmt_id += 1 ; let defer_tick_ident = syn :: Ident :: new (& format ! ("stream_{}" , defer_tick_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # defer_tick_ident = # input_ident -> defer_tick_lazy () ; }) ; (defer_tick_ident , input_location_id) } HfPlusNode :: Enumerate (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let enumerate_id = * next_stmt_id ; * next_stmt_id += 1 ; let enumerate_ident = syn :: Ident :: new (& format ! ("stream_{}" , enumerate_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # enumerate_ident = # input_ident -> enumerate () ; }) ; (enumerate_ident , input_location_id) } HfPlusNode :: Inspect { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let inspect_id = * next_stmt_id ; * next_stmt_id += 1 ; let inspect_ident = syn :: Ident :: new (& format ! ("stream_{}" , inspect_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # inspect_ident = # input_ident -> inspect (# f) ; }) ; (inspect_ident , input_location_id) } HfPlusNode :: Unique (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let unique_id = * next_stmt_id ; * next_stmt_id += 1 ; let unique_ident = syn :: Ident :: new (& format ! ("stream_{}" , unique_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # unique_ident = # input_ident -> unique ::<'tick > () ; }) ; (unique_ident , input_location_id) } HfPlusNode :: Fold { .. } | HfPlusNode :: FoldKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Fold { .. }) { parse_quote ! (fold) } else { parse_quote ! (fold_keyed) } ; let (HfPlusNode :: Fold { init , acc , input } | HfPlusNode :: FoldKeyed { init , acc , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let fold_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'static > (# init , # acc) ; }) ; } else { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'tick > (# init , # acc) ; }) ; } (fold_ident , input_location_id) } HfPlusNode :: Reduce { .. } | HfPlusNode :: ReduceKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Reduce { .. }) { parse_quote ! (reduce) } else { parse_quote ! (reduce_keyed) } ; let (HfPlusNode :: Reduce { f , input } | HfPlusNode :: ReduceKeyed { f , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let reduce_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'static > (# f) ; }) ; } else { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'tick > (# f) ; }) ; } (reduce_ident , input_location_id) } HfPlusNode :: Network { from_location : _ , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input , } => { let (sink_expr , source_expr , _connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { panic ! ("Expected the network to be finalized") } DebugInstantiate :: Finalized (sink , source , connect_fn) => { (sink , source , connect_fn) } } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sender_builder = graph_builders . entry (input_location_id) . or_default () ; if let Some (serialize_pipeline) = serialize_pipeline { sender_builder . add_statement (parse_quote ! { # input_ident -> # serialize_pipeline -> dest_sink (# sink_expr) ; }) ; } else { sender_builder . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink_expr) ; }) ; } let to_id = match to_location { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let receiver_builder = graph_builders . entry (* to_id) . or_default () ; let receiver_stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let receiver_stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , receiver_stream_id) , Span :: call_site ()) ; if let Some (deserialize_pipeline) = deserialize_pipeline { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) -> # deserialize_pipeline ; }) ; } else { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) ; }) ; } (receiver_stream_ident , * to_id) } } } } } pub mod persist_pullup { pub use std :: cell :: RefCell ; pub use std :: collections :: HashSet ; pub use std :: ops :: Deref ; pub use crate :: ir :: * ; pub fn persist_pullup_node < 'a > (node : & mut HfPlusNode < 'a > , seen_tees : & mut SeenTees < 'a > , persist_pulled_tees : & mut HashSet < * const RefCell < HfPlusNode < 'a > > > ,) { node . transform_children (| n , s | persist_pullup_node (n , s , persist_pulled_tees) , seen_tees ,) ; match node { HfPlusNode :: Unpersist (HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Unpersist (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Delta (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Delta (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Tee { inner } => { if persist_pulled_tees . contains (& (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >)) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } else { let inner_borrow = inner . borrow () ; if let HfPlusNode :: Persist (_) = inner_borrow . deref () { drop (inner_borrow) ; persist_pulled_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >) ; if let HfPlusNode :: Persist (box behind_persist) = inner . replace (HfPlusNode :: Placeholder) { * inner . borrow_mut () = behind_persist ; } else { unreachable ! () } * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } } } HfPlusNode :: Map { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Map { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Map { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: FlatMap { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: FlatMap { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: FlatMap { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Filter { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Filter { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Filter { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Network { input : box HfPlusNode :: Persist (_) , .. } => { if let HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Union (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Union (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Union (left , right))) ; } else { unreachable ! () } } HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: CrossProduct (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,) ,)))) ; } else { unreachable ! () } } HfPlusNode :: Join (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Join (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: Join (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,))))) ; } else { unreachable ! () } } _ => { } } } pub fn persist_pullup (ir : Vec < HfPlusLeaf >) -> Vec < HfPlusLeaf > { let mut seen_tees = Default :: default () ; let mut persist_pulled_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| n , s | persist_pullup_node (n , s , & mut persist_pulled_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn persist_pullup_through_map () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } # [test] fn persist_pullup_behind_tee () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; let before_tee = flow . source_iter (& process , q ! (0 .. 10)) . tick_batch () . persist () ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } } } pub mod profiler { pub use std :: cell :: RefCell ; pub use hydroflow :: futures :: channel :: mpsc :: UnboundedSender ; pub use stageleft :: * ; pub use crate as hydroflow_plus ; pub use crate :: ir :: * ; pub use crate :: RuntimeContext ; pub fn increment_counter (count : & mut u64) { * count += 1 ; } pub fn quoted_any_fn < 'a , F : Fn (& usize) + 'a , Q : IntoQuotedMut < 'a , F > > (q : Q) -> Q { q } # [doc = " Add a profiling node before each node to count the cardinality of its input"] pub fn add_profiling_node < 'a > (node : & mut HfPlusNode < 'a > , _context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > , id : & mut u32 , seen_tees : & mut SeenTees < 'a > ,) { let my_id = * id ; * id += 1 ; node . transform_children (| node , seen_tees | { add_profiling_node (node , _context , counters , counter_queue , id , seen_tees) } , seen_tees ,) ; let orig_node = std :: mem :: replace (node , HfPlusNode :: Placeholder) ; * node = HfPlusNode :: Inspect { f : quoted_any_fn (q ! ({ counter_queue . borrow () . unbounded_send ((my_id as usize , counters . borrow () [my_id as usize])) . unwrap () ; counters . borrow_mut () [my_id as usize] = 0 ; move | _ | { hydroflow_plus :: profiler :: increment_counter (& mut counters . borrow_mut () [my_id as usize] ,) ; } })) . splice () . into () , input : Box :: new (orig_node) , } } # [doc = " Count the cardinality of each input and periodically output to a file"] pub fn profiling < 'a > (ir : Vec < HfPlusLeaf < 'a > > , context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > ,) -> Vec < HfPlusLeaf < 'a > > { let mut id = 0 ; let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | { add_profiling_node (node , context , counters , counter_queue , & mut id , seen_tees) } , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn profiler_wrapping_all_operators () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let runtime_context = flow . runtime_context () ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (& built . ir ()) ; let counters = RuntimeData :: new ("Fake") ; let counter_queue = RuntimeData :: new ("Fake") ; let pushed_down = built . with_default_optimize () . optimize_with (| ir | super :: profiling (ir , runtime_context , counters , counter_queue)) ; insta :: assert_debug_snapshot ! (& pushed_down . ir ()) ; let _ = pushed_down . compile_no_network :: < MultiGraph > () ; } } } pub mod properties { pub use std :: collections :: HashSet ; pub use stageleft :: * ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , SeenTees } ; pub use crate :: properties :: PropertyDatabase ; # [doc = " Allows us to convert the hydroflow datatype for folds to a binary operation for the algebra"] # [doc = " property tests."] # [allow (dead_code)] pub fn convert_hf_to_binary < I , A : Default , F : Fn (& mut A , I) > (f : F) -> impl Fn (I , I) -> A { move | a , b | { let mut acc = Default :: default () ; f (& mut acc , a) ; f (& mut acc , b) ; acc } } # [cfg (stageleft_macro)] impl PropertyDatabase { # [doc = " Tags the expression as commutative."] pub fn add_commutative_tag < 'a , I , A , F : Fn (& mut A , I) , Q : Quoted < 'a , F > + Clone > (& mut self , expr : Q ,) -> Q { let expr_clone = expr . clone () ; self . commutative . insert (expr_clone . splice ()) ; expr } pub fn is_tagged_commutative (& self , expr : & syn :: Expr) -> bool { self . commutative . contains (expr) } } pub fn properties_optimize_node < 'a > (node : & mut HfPlusNode < 'a > , db : & PropertyDatabase , seen_tees : & mut SeenTees < 'a > ,) { node . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , seen_tees ,) ; match node { HfPlusNode :: ReduceKeyed { f , .. } if db . is_tagged_commutative (& f . 0) => { dbg ! ("IDENTIFIED COMMUTATIVE OPTIMIZATION for {:?}" , & f) ; } _ => { } } } pub fn properties_optimize < 'a > (ir : Vec < HfPlusLeaf < 'a > > , db : & PropertyDatabase ,) -> Vec < HfPlusLeaf < 'a > > { let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use super :: * ; use crate :: deploy :: SingleProcessGraph ; use crate :: FlowBuilder ; # [test] fn test_property_database () { let mut db = PropertyDatabase :: default () ; assert ! (! db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; let _ = db . add_commutative_tag (q ! (| a : & mut i32 , b : i32 | * a += b)) ; assert ! (db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; } # [test] fn test_property_optimized () { let flow = FlowBuilder :: new () ; let mut database = PropertyDatabase :: default () ; let process = flow . process :: < () > () ; let counter_func = q ! (| count : & mut i32 , _ | * count += 1) ; let _ = database . add_commutative_tag (counter_func) ; flow . source_iter (& process , q ! (vec ! [])) . map (q ! (| string : String | (string , ()))) . tick_batch () . fold_keyed (q ! (|| 0) , counter_func) . all_ticks () . for_each (q ! (| (string , count) | println ! ("{}: {}" , string , count))) ; let built = flow . finalize () . optimize_with (| ir | properties_optimize (ir , & database)) . with_default_optimize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let _ = built . compile_no_network :: < SingleProcessGraph > () ; } } } pub use crate :: RuntimeContext ; # [cfg (stageleft_macro)] impl Copy for RuntimeContext < '_ > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Context > for RuntimeContext < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (quote ! (& context))) } } pub use crate :: HfCompiled ; # [cfg (stageleft_macro)] impl < 'a , ID > HfCompiled < 'a , ID > { pub fn hydroflow_ir (& self) -> & BTreeMap < usize , HydroflowGraph > { & self . hydroflow_ir } } # [cfg (stageleft_macro)] impl < 'a > HfCompiled < 'a , usize > { pub fn with_dynamic_id (self , id : impl Quoted < 'a , usize >) -> HfBuiltWithId < 'a > { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; let mut conditioned_tokens = None ; for (subgraph_id , flat_graph) in self . hydroflow_ir { let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; let my_extra_stmts = self . extra_stmts . get (& subgraph_id) . cloned () . unwrap_or_default () ; if let Some (conditioned_tokens) = conditioned_tokens . as_mut () { * conditioned_tokens = syn :: parse_quote ! { # conditioned_tokens else if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } } ; } else { conditioned_tokens = Some (syn :: parse_quote ! { if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } }) ; } } let conditioned_tokens : TokenStream = conditioned_tokens . unwrap () ; let id = id . splice () ; HfBuiltWithId { tokens : syn :: parse_quote ! ({ let __given_id = # id ; # conditioned_tokens else { panic ! ("Invalid node id: {}" , __given_id) ; } }) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfCompiled < 'a , () > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfCompiled < 'a , () > { fn to_tokens (mut self) -> (Option < TokenStream > , Option < TokenStream >) { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; if self . hydroflow_ir . len () != 1 { panic ! ("Expected exactly one subgraph in the Hydroflow IR") ; } let flat_graph = self . hydroflow_ir . remove (& 0) . unwrap () ; let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; (None , Some (tokens)) } } pub use crate :: HfBuiltWithId ; # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfBuiltWithId < 'a > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfBuiltWithId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (self . tokens)) } }
[INFO] [stdout]   |
[INFO] [stdout] help: ...otherwise replace it with an invocation of macro `deref`
[INFO] [stdout]   |
[INFO] [stdout] 1 - pub use std :: collections :: BTreeMap ; pub use std :: marker :: PhantomData ; pub use hydroflow :: scheduled :: context :: Context ; pub use hydroflow :: scheduled :: graph :: Hydroflow ; pub use hydroflow :: * ; pub use lang :: graph :: { partition_graph , HydroflowGraph } ; pub use proc_macro2 :: TokenStream ; pub use quote :: quote ; pub use stageleft :: runtime_support :: FreeVariable ; pub use stageleft :: Quoted ; pub mod runtime_support { pub use bincode ; } pub mod stream { pub use std :: cell :: RefCell ; pub use std :: hash :: Hash ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow :: bytes :: Bytes ; pub use hydroflow :: futures :: Sink ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: quote ; pub use serde :: de :: DeserializeOwned ; pub use serde :: Serialize ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use syn :: parse_quote ; pub use crate :: builder :: { ClusterIds , FlowLeaves } ; pub use crate :: cycle :: { CycleCollection , CycleComplete } ; pub use crate :: ir :: { DebugInstantiate , HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { CanSend , Location , LocationId } ; pub use crate :: { Cluster , Optional , Singleton } ; pub use crate :: stream :: Unbounded ; pub use crate :: stream :: Bounded ; pub use crate :: stream :: NoTick ; pub use crate :: stream :: Tick ; pub use crate :: stream :: Stream ; # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Stream { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Stream < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Stream { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , C , N > > ,) -> Stream < 'a , (T , O) , W , C , N > where O : Clone , { let other : Optional < 'a , O , Bounded , C , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn cross_product < O > (self , other : Stream < 'a , O , W , C , N >) -> Stream < 'a , (T , O) , W , C , N > where T : Clone , O : Clone , { if self . location_kind != other . location_kind { panic ! ("cross_product must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossProduct (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn union (self , other : Stream < 'a , T , W , C , N >) -> Stream < 'a , T , W , C , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn dest_sink < S : Unpin + Sink < T > + 'a > (self , sink : impl Quoted < 'a , S >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: DestSink { sink : sink . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn first (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } # [doc = " Allow this stream through if the other stream has elements, otherwise the output is empty."] pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } # [doc = " Allow this stream through if the other stream is empty, otherwise the output is empty."] pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn enumerate (self) -> Stream < 'a , (usize , T) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Enumerate (Box :: new (self . ir_node . into_inner ())) ,) } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn sort (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Ord , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Sort (Box :: new (self . ir_node . into_inner ())) ,) } pub fn count (self) -> Singleton < 'a , usize , Bounded , Tick , N > { self . fold (q ! (|| 0usize) , q ! (| count , _ | * count += 1)) } pub fn delta (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } pub fn unique (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Eq + Hash , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unique (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn tick_batch (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_prefix (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { self . tick_batch () . persist () } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn for_each < F : Fn (T) + 'a > (self , f : impl IntoQuotedMut < 'a , F >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: ForEach { input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , f : f . splice () . into () , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Unbounded , NoTick , N > { pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . tick_batch () . continue_if (samples . first ()) . all_ticks () } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Unbounded , NoTick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , C , N : Location > Stream < 'a , T , Bounded , C , N > { pub fn filter_not_in (self , other : Stream < 'a , T , Bounded , C , N >) -> Stream < 'a , T , Bounded , C , N > where T : Eq + Hash , { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Difference (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Stream < 'a , & T , W , C , N > { pub fn cloned (self) -> Stream < 'a , T , W , C , N > { self . map (q ! (| d | d . clone ())) } } # [cfg (stageleft_macro)] impl < 'a , K , V1 , W , C , N : Location > Stream < 'a , (K , V1) , W , C , N > { pub fn join < W2 , V2 > (self , n : Stream < 'a , (K , V2) , W2 , C , N > ,) -> Stream < 'a , (K , (V1 , V2)) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Join (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } pub fn anti_join < W2 > (self , n : Stream < 'a , K , W2 , C , N >) -> Stream < 'a , (K , V1) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("anti_join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: AntiJoin (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , K : Eq + Hash , V , N : Location > Stream < 'a , (K , V) , Bounded , Tick , N > { pub fn fold_keyed < A , I : Fn () -> A + 'a , F : Fn (& mut A , V) + 'a > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , A) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FoldKeyed { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce_keyed < F : Fn (& mut V , V) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , V) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: ReduceKeyed { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } pub fn get_this_crate () -> TokenStream { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , Span :: call_site ()) ; quote ! { # ident } } } } pub fn serialize_bincode < T : Serialize > (is_demux : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if is_demux { parse_quote ! { map (| (id , data) | { (id , # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into ()) }) } } else { parse_quote ! { map (| data | { # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into () }) } } } pub fn deserialize_bincode < T : DeserializeOwned > (tagged : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if tagged { parse_quote ! { map (| res | { let (id , b) = res . unwrap () ; (id , # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& b) . unwrap ()) }) } } else { parse_quote ! { map (| res | { # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& res . unwrap ()) . unwrap () }) } } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn send_bincode < N2 : Location , CoreType > (self , other : & N2 ,) -> Stream < 'a , N :: Out < CoreType > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T > , CoreType : Serialize + DeserializeOwned , { let serialize_pipeline = Some (serialize_bincode :: < CoreType > (N :: is_demux ())) ; let deserialize_pipeline = Some (deserialize_bincode :: < CoreType > (N :: is_tagged ())) ; Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bytes < N2 : Location > (self , other : & N2 ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T > , { Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline : None , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline : if N :: is_tagged () { Some (parse_quote ! (map (| (id , b) | (id , b . unwrap () . freeze ())))) } else { Some (parse_quote ! (map (| b | b . unwrap () . freeze ()))) } , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bincode_interleaved < N2 : Location , Tag , CoreType > (self , other : & N2 ,) -> Stream < 'a , CoreType , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T , Out < CoreType > = (Tag , CoreType) > , CoreType : Serialize + DeserializeOwned , { self . send_bincode :: < N2 , CoreType > (other) . map (q ! (| (_ , b) | b)) } pub fn send_bytes_interleaved < N2 : Location , Tag > (self , other : & N2 ,) -> Stream < 'a , Bytes , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T , Out < Bytes > = (Tag , Bytes) > , { self . send_bytes :: < N2 > (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bincode < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < T > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) > , T : Clone + Serialize + DeserializeOwned , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bincode (other) } pub fn broadcast_bincode_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , T , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) , Out < T > = (Tag , T) > + 'a , T : Clone + Serialize + DeserializeOwned , { self . broadcast_bincode (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bytes < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) > + 'a , T : Clone , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bytes (other) } pub fn broadcast_bytes_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , Bytes , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) , Out < Bytes > = (Tag , Bytes) > + 'a , T : Clone , { self . broadcast_bytes (other) . map (q ! (| (_ , b) | b)) } } } pub use stream :: { Bounded , NoTick , Stream , Tick , Unbounded } ; pub mod singleton { pub use std :: cell :: RefCell ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use crate :: builder :: FlowLeaves ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial , CycleComplete } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: Stream ; pub use crate :: singleton :: CrossResult ; # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Singleton < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Singleton :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } pub use crate :: singleton :: Singleton ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Singleton { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleComplete < 'a > for Singleton < 'a , T , Bounded , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleCollectionWithInitial < 'a > for Singleton < 'a , T , Bounded , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , initial : Self , l : LocationId ,) -> Self { Singleton :: new (l , ir_leaves , HfPlusNode :: Union (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , }) , initial . ir_node . into_inner () . into () ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Singleton < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Singleton { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , U , W , C , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (Self :: other_ir_node (other)) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Singleton < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CrossSingleton (Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , Box :: new (HfPlusNode :: Unpersist (Box :: new (Self :: other_ir_node (other)))) ,))) ,) } } pub use crate :: singleton :: Optional ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Optional { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } pub fn some (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: new (singleton . location_kind , singleton . ir_leaves , singleton . ir_node . into_inner () ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > From < Singleton < 'a , T , W , C , N > > for Optional < 'a , T , W , C , N > { fn from (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: some (singleton) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Optional < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Optional { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn into_stream (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , Tick , N > > ,) -> Optional < 'a , (T , O) , Bounded , Tick , N > where O : Clone , { let other : Optional < 'a , O , Bounded , Tick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn union (self , other : Optional < 'a , T , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Optional < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_samples (self) -> Stream < 'a , T , Unbounded , NoTick , N > { self . latest_tick () . all_ticks () } pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . latest_tick () . continue_if (samples . first ()) . latest () . tick_samples () } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Unbounded , NoTick , N > > ,) -> Optional < 'a , (T , O) , Unbounded , NoTick , N > where O : Clone , { let other : Optional < 'a , O , Unbounded , NoTick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } self . latest_tick () . cross_singleton (other . latest_tick ()) . latest () } } } pub use singleton :: { Optional , Singleton } ; pub mod location { pub use std :: marker :: PhantomData ; pub use crate :: location :: LocationId ; pub use crate :: location :: Location ; pub use crate :: location :: Process ; # [cfg (stageleft_macro)] impl < P > Clone for Process < P > { fn clone (& self) -> Self { Process { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < P > Location for Process < P > { fn id (& self) -> LocationId { LocationId :: Process (self . id) } } pub use crate :: location :: Cluster ; # [cfg (stageleft_macro)] impl < C > Clone for Cluster < C > { fn clone (& self) -> Self { Cluster { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < C > Location for Cluster < C > { fn id (& self) -> LocationId { LocationId :: Cluster (self . id) } } pub use crate :: location :: CanSend ; # [cfg (stageleft_macro)] impl < P1 , P2 > CanSend < Process < P2 > > for Process < P1 > { type In < T > = T ; type Out < T > = T ; fn is_demux () -> bool { false } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < P1 , C2 > CanSend < Cluster < C2 > > for Process < P1 > { type In < T > = (u32 , T) ; type Out < T > = T ; fn is_demux () -> bool { true } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < C1 , P2 > CanSend < Process < P2 > > for Cluster < C1 > { type In < T > = T ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { false } fn is_tagged () -> bool { true } } # [cfg (stageleft_macro)] impl < C1 , C2 > CanSend < Cluster < C2 > > for Cluster < C1 > { type In < T > = (u32 , T) ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { true } fn is_tagged () -> bool { true } } } pub use location :: { Cluster , Process } ; pub mod deploy { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use stageleft :: Quoted ; pub mod graphs { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use super :: { LocalDeploy , Node , ProcessSpec } ; pub use crate :: deploy :: graphs :: SingleProcessGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for SingleProcessGraph { type Process = SingleNode ; type Cluster = SingleNode ; type Meta = () ; type GraphId = () ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { SingleNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { SingleNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , SingleProcessGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> SingleNode { SingleNode { } } } pub use crate :: deploy :: graphs :: SingleNode ; # [cfg (stageleft_macro)] impl Node for SingleNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } pub use crate :: deploy :: graphs :: MultiGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for MultiGraph { type Process = MultiNode ; type Cluster = MultiNode ; type Meta = () ; type GraphId = usize ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { MultiNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { MultiNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , MultiGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> MultiNode { MultiNode { } } } pub use crate :: deploy :: graphs :: MultiNode ; # [cfg (stageleft_macro)] impl Node for MultiNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } } pub use graphs :: * ; pub use crate :: deploy :: LocalDeploy ; pub use crate :: deploy :: Deploy ; # [cfg (stageleft_macro)] impl < 'a , T : Deploy < 'a , Process = N , Cluster = C , Meta = M , GraphId = R > , N : Node < Meta = M > , C : Node < Meta = M > , M : Default , R , > LocalDeploy < 'a > for T { type Process = N ; type Cluster = C ; type Meta = M ; type GraphId = R ; fn has_trivial_node () -> bool { < T as Deploy < 'a > > :: has_trivial_node () } fn trivial_process (id : usize) -> Self :: Process { < T as Deploy < 'a > > :: trivial_process (id) } fn trivial_cluster (id : usize) -> Self :: Cluster { < T as Deploy < 'a > > :: trivail_cluster (id) } } pub use crate :: deploy :: ProcessSpec ; pub use crate :: deploy :: ClusterSpec ; pub use crate :: deploy :: Node ; } pub use deploy :: { ClusterSpec , Deploy , ProcessSpec } ; pub mod cycle { pub use std :: marker :: PhantomData ; pub use crate :: builder :: FlowLeaves ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: cycle :: CycleComplete ; pub use crate :: cycle :: CycleCollection ; pub use crate :: cycle :: CycleCollectionWithInitial ; pub use crate :: cycle :: HfCycle ; # [cfg (stageleft_macro)] impl < 'a , S : CycleComplete < 'a > > HfCycle < 'a , S > { pub fn complete (self , stream : S) { let ident = self . ident ; S :: complete (stream , ident) } } } pub use cycle :: HfCycle ; pub mod builder { pub use std :: cell :: RefCell ; pub use std :: collections :: HashMap ; pub use std :: marker :: PhantomData ; pub use std :: rc :: Rc ; pub use std :: time :: Duration ; pub use hydroflow :: futures :: stream :: Stream as FuturesStream ; pub use hydroflow :: { tokio , tokio_stream } ; pub use internal :: TokenStream ; pub use proc_macro2 :: Span ; pub use quote :: quote ; pub use runtime_support :: FreeVariable ; pub use stageleft :: * ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Cluster , Location , LocationId , Process } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: { HfCycle , Optional , RuntimeContext , Singleton , Stream } ; pub mod built { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use hydroflow_lang :: graph :: { eliminate_extra_unions_tees , HydroflowGraph } ; pub use super :: deploy :: { DeployFlow , DeployResult } ; pub use crate :: deploy :: { ClusterSpec , Deploy , LocalDeploy , ProcessSpec } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Cluster , Process } ; pub use crate :: HfCompiled ; pub use crate :: builder :: built :: BuiltFlow ; # [cfg (stageleft_macro)] impl < 'a > Drop for BuiltFlow < 'a > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped BuiltFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn ir (& self) -> & Vec < HfPlusLeaf < 'a > > { & self . ir } pub fn optimize_with (mut self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> BuiltFlow < 'a > { self . used = true ; BuiltFlow { ir : f (std :: mem :: take (& mut self . ir)) , processes : std :: mem :: take (& mut self . processes) , clusters : std :: mem :: take (& mut self . clusters) , used : false , _phantom : PhantomData , } } } pub fn build_inner (ir : & mut Vec < HfPlusLeaf >) -> BTreeMap < usize , HydroflowGraph > { let mut builders = BTreeMap :: new () ; let mut built_tees = HashMap :: new () ; let mut next_stmt_id = 0 ; for leaf in ir { leaf . emit (& mut builders , & mut built_tees , & mut next_stmt_id) ; } builders . into_iter () . map (| (k , v) | { let (mut flat_graph , _ , _) = v . build () ; eliminate_extra_unions_tees (& mut flat_graph) ; (k , flat_graph) }) . collect () } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn compile_no_network < D : LocalDeploy < 'a > > (mut self) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; HfCompiled { hydroflow_ir : build_inner (& mut self . ir) , extra_stmts : BTreeMap :: new () , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> BuiltFlow < 'a > { self . optimize_with (crate :: persist_pullup :: persist_pullup) } fn into_deploy < D : LocalDeploy < 'a > > (mut self) -> DeployFlow < 'a , D > { self . used = true ; let processes = if D :: has_trivial_node () { self . processes . iter () . map (| id | (* id , D :: trivial_process (* id))) . collect () } else { HashMap :: new () } ; let clusters = if D :: has_trivial_node () { self . clusters . iter () . map (| id | (* id , D :: trivial_cluster (* id))) . collect () } else { HashMap :: new () } ; DeployFlow { ir : std :: mem :: take (& mut self . ir) , nodes : processes , clusters , used : false , _phantom : PhantomData , } } pub fn with_process < P , D : LocalDeploy < 'a > > (self , process : & Process < P > , spec : impl ProcessSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_process (process , spec) } pub fn with_cluster < C , D : LocalDeploy < 'a > > (self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_cluster (cluster , spec) } pub fn compile < D : Deploy < 'a > + 'a > (self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . into_deploy :: < D > () . compile (env) } pub fn deploy < D : Deploy < 'a , CompileEnv = () > + 'a > (self , env : & mut D :: InstantiateEnv ,) -> DeployResult < 'a , D > { self . into_deploy :: < D > () . deploy (env) } } } pub mod deploy { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use proc_macro2 :: Span ; pub use stageleft :: Quoted ; pub use super :: built :: build_inner ; pub use crate :: deploy :: { LocalDeploy , Node } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: { Cluster , ClusterSpec , Deploy , HfCompiled , Process , ProcessSpec } ; pub use crate :: builder :: deploy :: DeployFlow ; # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > Drop for DeployFlow < 'a , D > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped DeployFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > DeployFlow < 'a , D > { pub fn with_process < P > (mut self , process : & Process < P > , spec : impl ProcessSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < P > () . to_string () ; self . nodes . insert (process . id , spec . build (process . id , & tag_name)) ; self } pub fn with_cluster < C > (mut self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < C > () . to_string () ; self . clusters . insert (cluster . id , spec . build (cluster . id , & tag_name)) ; self } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployFlow < 'a , D > { pub fn compile (mut self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; let mut seen_tees : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | leaf . compile_network :: < D > (env , & mut seen_tees , & self . nodes , & self . clusters)) . collect () ; let extra_stmts = self . extra_stmts (env) ; HfCompiled { hydroflow_ir : build_inner (& mut ir_leaves_networked) , extra_stmts , _phantom : PhantomData , } } fn extra_stmts (& self , env : & < D as Deploy < 'a > > :: CompileEnv) -> BTreeMap < usize , Vec < syn :: Stmt > > { let all_locations_count = self . nodes . len () + self . clusters . len () ; let mut extra_stmts : BTreeMap < usize , Vec < syn :: Stmt > > = BTreeMap :: new () ; for & c_id in self . clusters . keys () { let self_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , c_id) , Span :: call_site () ,) ; let self_id_expr = D :: cluster_self_id (env) . splice () ; extra_stmts . entry (c_id) . or_default () . push (syn :: parse_quote ! { let # self_id_ident = # self_id_expr ; }) ; for other_location in 0 .. all_locations_count { let other_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , c_id) , Span :: call_site () ,) ; let other_id_expr = D :: cluster_ids (env , c_id) . splice () ; extra_stmts . entry (other_location) . or_default () . push (syn :: parse_quote ! { let # other_id_ident = # other_id_expr ; }) ; } } extra_stmts } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a , CompileEnv = () > > DeployFlow < 'a , D > { # [must_use] pub fn deploy (mut self , env : & mut D :: InstantiateEnv) -> DeployResult < 'a , D > { self . used = true ; let mut seen_tees_instantiate : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | { leaf . compile_network :: < D > (& () , & mut seen_tees_instantiate , & self . nodes , & self . clusters ,) }) . collect () ; let mut compiled = build_inner (& mut ir_leaves_networked) ; let mut extra_stmts = self . extra_stmts (& ()) ; let mut meta = D :: Meta :: default () ; let (mut processes , mut clusters) = (std :: mem :: take (& mut self . nodes) . into_iter () . map (| (node_id , node) | { node . instantiate (env , & mut meta , compiled . remove (& node_id) . unwrap () , extra_stmts . remove (& node_id) . unwrap_or_default () ,) ; (node_id , node) }) . collect :: < HashMap < _ , _ > > () , std :: mem :: take (& mut self . clusters) . into_iter () . map (| (cluster_id , cluster) | { cluster . instantiate (env , & mut meta , compiled . remove (& cluster_id) . unwrap () , extra_stmts . remove (& cluster_id) . unwrap_or_default () ,) ; (cluster_id , cluster) }) . collect :: < HashMap < _ , _ > > () ,) ; for node in processes . values_mut () { node . update_meta (& meta) ; } for cluster in clusters . values_mut () { cluster . update_meta (& meta) ; } let mut seen_tees_connect = HashMap :: new () ; for leaf in ir_leaves_networked { leaf . connect_network (& mut seen_tees_connect) ; } DeployResult { processes , clusters , } } } pub use crate :: builder :: deploy :: DeployResult ; # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployResult < 'a , D > { pub fn get_process < P > (& self , p : & Process < P >) -> & D :: Process { let id = match p . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . processes . get (& id) . unwrap () } pub fn get_cluster < C > (& self , c : & Cluster < C >) -> & D :: Cluster { let id = match c . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . clusters . get (& id) . unwrap () } } } # [doc = " Tracks the leaves of the dataflow IR. This is referenced by"] # [doc = " `Stream` and `HfCycle` to build the IR. The inner option will"] # [doc = " be set to `None` when this builder is finalized."] pub type FlowLeaves < 'a > = Rc < RefCell < Option < Vec < HfPlusLeaf < 'a > > > > > ; pub use crate :: builder :: ClusterIds ; # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Vec < u32 > > for ClusterIds < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , & 'a Vec < u32 > > for ClusterIds < 'a > { } # [derive (Copy , Clone)] pub struct ClusterSelfId < 'a > { pub id : usize , pub _phantom : PhantomData < & 'a mut & 'a u32 > , } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < u32 > for ClusterSelfId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , u32 > for ClusterSelfId < 'a > { } pub use crate :: builder :: FlowBuilder ; # [cfg (stageleft_macro)] impl < 'a > Drop for FlowBuilder < 'a > { fn drop (& mut self) { if ! self . finalized { panic ! ("Dropped FlowBuilder without finalizing, you may have forgotten to call `with_default_optimize`, `optimize_with`, or `finalize`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > QuotedContext for FlowBuilder < 'a > { fn create () -> Self { FlowBuilder :: new () } } # [cfg (stageleft_macro)] impl < 'a > FlowBuilder < 'a > { # [allow (clippy :: new_without_default)] pub fn new () -> FlowBuilder < 'a > { FlowBuilder { ir_leaves : Rc :: new (RefCell :: new (Some (Vec :: new ()))) , nodes : RefCell :: new (vec ! []) , clusters : RefCell :: new (vec ! []) , cycle_ids : RefCell :: new (HashMap :: new ()) , next_node_id : RefCell :: new (0) , finalized : false , _phantom : PhantomData , } } pub fn finalize (mut self) -> built :: BuiltFlow < 'a > { self . finalized = true ; built :: BuiltFlow { ir : self . ir_leaves . borrow_mut () . take () . unwrap () , processes : self . nodes . replace (vec ! []) , clusters : self . clusters . replace (vec ! []) , used : false , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> built :: BuiltFlow < 'a > { self . finalize () . with_default_optimize () } pub fn optimize_with (self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> built :: BuiltFlow < 'a > { self . finalize () . optimize_with (f) } pub fn ir_leaves (& self) -> & FlowLeaves < 'a > { & self . ir_leaves } pub fn process < P > (& self) -> Process < P > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . nodes . borrow_mut () . push (id) ; Process { id , _phantom : PhantomData , } } pub fn cluster < C > (& self) -> Cluster < C > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . clusters . borrow_mut () . push (id) ; Cluster { id , _phantom : PhantomData , } } pub fn runtime_context (& self) -> RuntimeContext < 'a > { RuntimeContext { _phantom : PhantomData , } } pub fn cluster_members < C > (& self , cluster : & Cluster < C > ,) -> impl Quoted < 'a , & 'a Vec < u32 > > + Copy + 'a { ClusterIds { id : cluster . id , _phantom : PhantomData , } } pub fn cluster_self_id < C > (& self , cluster : & Cluster < C >) -> impl Quoted < 'a , u32 > + Copy + 'a { ClusterSelfId { id : cluster . id , _phantom : PhantomData , } } pub fn spin < L : Location > (& self , on : & L) -> Stream < 'a , () , Unbounded , NoTick , L > { Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Spin () , location_kind : on . id () , })) ,) } pub fn spin_batch < L : Location > (& self , on : & L , batch_size : impl Quoted < 'a , usize > + Copy + 'a ,) -> Stream < 'a , () , Bounded , Tick , L > { self . spin (on) . flat_map (q ! (move | _ | 0 .. batch_size)) . map (q ! (| _ | ())) . tick_batch () } pub fn source_stream < T , E : FuturesStream < Item = T > + Unpin , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Unbounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Stream (e . into ()) , location_kind : on . id () , })) ,) } pub fn source_iter < T , E : IntoIterator < Item = T > , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Bounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , })) ,) } pub fn singleton < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Singleton < 'a , T , Bounded , NoTick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Singleton :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,)))) ,) } pub fn singleton_first_tick < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Optional < 'a , T , Bounded , Tick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,) } pub fn source_interval < L : Location > (& self , on : & L , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , () , Unbounded , NoTick , L > { let interval = interval . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : on . id () , })) ,) } pub fn source_interval_delayed < L : Location > (& self , on : & L , delay : impl Quoted < 'a , Duration > + Copy + 'a , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , tokio :: time :: Instant , Unbounded , NoTick , L > { self . source_stream (on , q ! (tokio_stream :: wrappers :: IntervalStream :: new (tokio :: time :: interval_at (tokio :: time :: Instant :: now () + delay , interval))) ,) . tick_batch () . first () . latest () } pub fn cycle < S : CycleCollection < 'a > > (& self , on : & S :: Location) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , on . id ()) ,) } pub fn cycle_with_initial < S : CycleCollectionWithInitial < 'a > > (& self , on : & S :: Location , initial : S ,) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , initial , on . id ()) ,) } } } pub use builder :: FlowBuilder ; pub mod ir { pub use core :: panic ; pub use std :: cell :: RefCell ; pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow_lang :: graph :: FlatGraphBuilder ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: ToTokens ; pub use syn :: parse_quote ; pub use crate :: deploy :: Deploy ; pub use crate :: location :: LocationId ; pub use crate :: ir :: DebugExpr ; # [cfg (stageleft_macro)] impl From < syn :: Expr > for DebugExpr { fn from (expr : syn :: Expr) -> DebugExpr { DebugExpr (expr) } } # [cfg (stageleft_macro)] impl Deref for DebugExpr { type Target = syn :: Expr ; fn deref (& self) -> & Self :: Target { & self . 0 } } # [cfg (stageleft_macro)] impl ToTokens for DebugExpr { fn to_tokens (& self , tokens : & mut TokenStream) { self . 0 . to_tokens (tokens) ; } } # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugExpr { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "{}" , self . 0 . to_token_stream ()) } } pub use crate :: ir :: DebugInstantiate ; # [cfg (stageleft_macro)] impl < 'a > std :: fmt :: Debug for DebugInstantiate < 'a > { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<network instantiate>") } } pub use crate :: ir :: DebugPipelineFn ; # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugPipelineFn { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<function>") } } pub use crate :: ir :: HfPlusSource ; pub use crate :: ir :: HfPlusLeaf ; # [cfg (stageleft_macro)] impl < 'a > HfPlusLeaf < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . compile_network :: < D > (compile_env , s , nodes , clusters) ; } , seen_tees ,) } pub fn connect_network (self , seen_tees : & mut SeenTees < 'a >) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . connect_network (s) ; } , seen_tees ,) } pub fn transform_children (self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) -> HfPlusLeaf < 'a > { match self { HfPlusLeaf :: ForEach { f , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: ForEach { f , input } } HfPlusLeaf :: DestSink { sink , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: DestSink { sink , input } } HfPlusLeaf :: CycleSink { ident , location_kind , mut input , } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: CycleSink { ident , location_kind , input , } } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) { match self { HfPlusLeaf :: ForEach { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> for_each (# f) ; }) ; } HfPlusLeaf :: DestSink { sink , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink) ; }) ; } HfPlusLeaf :: CycleSink { ident , location_kind , input , } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; assert_eq ! (input_location_id , * location_id , "cycle_sink location mismatch") ; graph_builders . entry (* location_id) . or_default () . add_statement (parse_quote ! { # ident = # input_ident ; }) ; } } } } pub use crate :: ir :: HfPlusNode ; pub type SeenTees < 'a > = HashMap < * const RefCell < HfPlusNode < 'a > > , Rc < RefCell < HfPlusNode < 'a > > > > ; # [cfg (stageleft_macro)] impl < 'a > HfPlusNode < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (& mut self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) { self . transform_children (| n , s | n . compile_network :: < D > (compile_env , s , nodes , clusters) , seen_tees ,) ; if let HfPlusNode :: Network { from_location , to_location , instantiate_fn , .. } = self { let (sink_expr , source_expr , connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { let ((sink , source) , connect_fn) = match (from_location , to_location) { (LocationId :: Process (from) , LocationId :: Process (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: o2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Process (from) , LocationId :: Cluster (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: o2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Process (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: m2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Cluster (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: m2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } } ; (sink , source , connect_fn) } DebugInstantiate :: Finalized (_ , _ , _) => panic ! ("network already finalized") , } ; * instantiate_fn = DebugInstantiate :: Finalized (sink_expr , source_expr , connect_fn) ; } } pub fn connect_network (& mut self , seen_tees : & mut SeenTees < 'a >) { self . transform_children (| n , s | n . connect_network (s) , seen_tees) ; if let HfPlusNode :: Network { instantiate_fn , .. } = self { match instantiate_fn { DebugInstantiate :: Building () => panic ! ("network not built") , DebugInstantiate :: Finalized (_ , _ , ref connect_fn) => { connect_fn () ; } } } } pub fn transform_children (& mut self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) { match self { HfPlusNode :: Placeholder => { panic ! () ; } HfPlusNode :: Source { .. } => { } HfPlusNode :: CycleSource { .. } => { } HfPlusNode :: Tee { inner } => { if let Some (transformed) = seen_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { * inner = transformed . clone () ; } else { let transformed_cell = Rc :: new (RefCell :: new (HfPlusNode :: Placeholder)) ; seen_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , transformed_cell . clone () ,) ; let mut orig = inner . replace (HfPlusNode :: Placeholder) ; transform (& mut orig , seen_tees) ; * transformed_cell . borrow_mut () = orig ; * inner = transformed_cell ; } } HfPlusNode :: Persist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Unpersist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Delta (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Union (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossProduct (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossSingleton (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Join (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Difference (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: AntiJoin (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Map { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FlatMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Filter { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FilterMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Sort (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: DeferTick (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Enumerate (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Inspect { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Unique (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Fold { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FoldKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Reduce { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: ReduceKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Network { input , .. } => { transform (input . as_mut () , seen_tees) ; } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) -> (syn :: Ident , usize) { match self { HfPlusNode :: Placeholder => { panic ! () } HfPlusNode :: Persist (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let persist_id = * next_stmt_id ; * next_stmt_id += 1 ; let persist_ident = syn :: Ident :: new (& format ! ("stream_{}" , persist_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # persist_ident = # inner_ident -> persist ::<'static > () ; }) ; (persist_ident , location) } HfPlusNode :: Unpersist (_) => { panic ! ("Unpersist is a marker node and should have been optimized away. This is likely a compiler bug.") } HfPlusNode :: Delta (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let delta_id = * next_stmt_id ; * next_stmt_id += 1 ; let delta_ident = syn :: Ident :: new (& format ! ("stream_{}" , delta_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # delta_ident = # inner_ident -> multiset_delta () ; }) ; (delta_ident , location) } HfPlusNode :: Source { source , location_kind , } => { let source_id = * next_stmt_id ; * next_stmt_id += 1 ; let source_ident = syn :: Ident :: new (& format ! ("stream_{}" , source_id) , Span :: call_site ()) ; let source_stmt = match source { HfPlusSource :: Stream (expr) => { parse_quote ! { # source_ident = source_stream (# expr) ; } } HfPlusSource :: Iter (expr) => { parse_quote ! { # source_ident = source_iter (# expr) ; } } HfPlusSource :: Interval (expr) => { parse_quote ! { # source_ident = source_interval (# expr) ; } } HfPlusSource :: Spin () => { parse_quote ! { # source_ident = spin () ; } } } ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; graph_builders . entry (* location_id) . or_default () . add_statement (source_stmt) ; (source_ident , * location_id) } HfPlusNode :: CycleSource { ident , location_kind , } => { let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; (ident . clone () , * location_id) } HfPlusNode :: Tee { inner } => { if let Some (ret) = built_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { ret . clone () } else { let (inner_ident , inner_location_id) = inner . borrow () . emit (graph_builders , built_tees , next_stmt_id) ; let tee_id = * next_stmt_id ; * next_stmt_id += 1 ; let tee_ident = syn :: Ident :: new (& format ! ("stream_{}" , tee_id) , Span :: call_site ()) ; let builder = graph_builders . entry (inner_location_id) . or_default () ; builder . add_statement (parse_quote ! { # tee_ident = # inner_ident -> tee () ; }) ; built_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , (tee_ident . clone () , inner_location_id) ,) ; (tee_ident , inner_location_id) } } HfPlusNode :: Union (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "union inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let union_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # union_ident = union () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [0] # union_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # union_ident ; }) ; (union_ident , left_location_id) } HfPlusNode :: CrossSingleton (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "cross_singleton inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let cross_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # cross_ident = cross_singleton () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [input] # cross_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [single] # cross_ident ; }) ; (cross_ident , left_location_id) } HfPlusNode :: CrossProduct (..) | HfPlusNode :: Join (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: CrossProduct (..)) { parse_quote ! (cross_join_multiset) } else { parse_quote ! (join_multiset) } ; let (HfPlusNode :: CrossProduct (left , right) | HfPlusNode :: Join (left , right)) = self else { unreachable ! () } ; let (left_inner , left_was_persist) = if let HfPlusNode :: Persist (left) = left . as_ref () { (left , true) } else { (left , false) } ; let (right_inner , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left_inner . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right_inner . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "join / cross product inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; match (left_was_persist , right_was_persist) { (true , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'static > () ; }) ; } (true , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'tick > () ; }) ; } (false , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } (false , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } } ; builder . add_statement (parse_quote ! { # left_ident -> [0] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Difference (..) | HfPlusNode :: AntiJoin (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Difference (..)) { parse_quote ! (difference_multiset) } else { parse_quote ! (anti_join_multiset) } ; let (HfPlusNode :: Difference (left , right) | HfPlusNode :: AntiJoin (left , right)) = self else { unreachable ! () } ; let (right , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "difference / anti join inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; if right_was_persist { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } else { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } builder . add_statement (parse_quote ! { # left_ident -> [pos] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [neg] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Map { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let map_id = * next_stmt_id ; * next_stmt_id += 1 ; let map_ident = syn :: Ident :: new (& format ! ("stream_{}" , map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # map_ident = # input_ident -> map (# f) ; }) ; (map_ident , input_location_id) } HfPlusNode :: FlatMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let flat_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let flat_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , flat_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # flat_map_ident = # input_ident -> flat_map (# f) ; }) ; (flat_map_ident , input_location_id) } HfPlusNode :: Filter { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_ident = # input_ident -> filter (# f) ; }) ; (filter_ident , input_location_id) } HfPlusNode :: FilterMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_map_ident = # input_ident -> filter_map (# f) ; }) ; (filter_map_ident , input_location_id) } HfPlusNode :: Sort (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sort_id = * next_stmt_id ; * next_stmt_id += 1 ; let sort_ident = syn :: Ident :: new (& format ! ("stream_{}" , sort_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # sort_ident = # input_ident -> sort () ; }) ; (sort_ident , input_location_id) } HfPlusNode :: DeferTick (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let defer_tick_id = * next_stmt_id ; * next_stmt_id += 1 ; let defer_tick_ident = syn :: Ident :: new (& format ! ("stream_{}" , defer_tick_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # defer_tick_ident = # input_ident -> defer_tick_lazy () ; }) ; (defer_tick_ident , input_location_id) } HfPlusNode :: Enumerate (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let enumerate_id = * next_stmt_id ; * next_stmt_id += 1 ; let enumerate_ident = syn :: Ident :: new (& format ! ("stream_{}" , enumerate_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # enumerate_ident = # input_ident -> enumerate () ; }) ; (enumerate_ident , input_location_id) } HfPlusNode :: Inspect { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let inspect_id = * next_stmt_id ; * next_stmt_id += 1 ; let inspect_ident = syn :: Ident :: new (& format ! ("stream_{}" , inspect_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # inspect_ident = # input_ident -> inspect (# f) ; }) ; (inspect_ident , input_location_id) } HfPlusNode :: Unique (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let unique_id = * next_stmt_id ; * next_stmt_id += 1 ; let unique_ident = syn :: Ident :: new (& format ! ("stream_{}" , unique_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # unique_ident = # input_ident -> unique ::<'tick > () ; }) ; (unique_ident , input_location_id) } HfPlusNode :: Fold { .. } | HfPlusNode :: FoldKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Fold { .. }) { parse_quote ! (fold) } else { parse_quote ! (fold_keyed) } ; let (HfPlusNode :: Fold { init , acc , input } | HfPlusNode :: FoldKeyed { init , acc , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let fold_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'static > (# init , # acc) ; }) ; } else { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'tick > (# init , # acc) ; }) ; } (fold_ident , input_location_id) } HfPlusNode :: Reduce { .. } | HfPlusNode :: ReduceKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Reduce { .. }) { parse_quote ! (reduce) } else { parse_quote ! (reduce_keyed) } ; let (HfPlusNode :: Reduce { f , input } | HfPlusNode :: ReduceKeyed { f , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let reduce_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'static > (# f) ; }) ; } else { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'tick > (# f) ; }) ; } (reduce_ident , input_location_id) } HfPlusNode :: Network { from_location : _ , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input , } => { let (sink_expr , source_expr , _connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { panic ! ("Expected the network to be finalized") } DebugInstantiate :: Finalized (sink , source , connect_fn) => { (sink , source , connect_fn) } } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sender_builder = graph_builders . entry (input_location_id) . or_default () ; if let Some (serialize_pipeline) = serialize_pipeline { sender_builder . add_statement (parse_quote ! { # input_ident -> # serialize_pipeline -> dest_sink (# sink_expr) ; }) ; } else { sender_builder . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink_expr) ; }) ; } let to_id = match to_location { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let receiver_builder = graph_builders . entry (* to_id) . or_default () ; let receiver_stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let receiver_stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , receiver_stream_id) , Span :: call_site ()) ; if let Some (deserialize_pipeline) = deserialize_pipeline { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) -> # deserialize_pipeline ; }) ; } else { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) ; }) ; } (receiver_stream_ident , * to_id) } } } } } pub mod persist_pullup { pub use std :: cell :: RefCell ; pub use std :: collections :: HashSet ; pub use std :: ops :: Deref ; pub use crate :: ir :: * ; pub fn persist_pullup_node < 'a > (node : & mut HfPlusNode < 'a > , seen_tees : & mut SeenTees < 'a > , persist_pulled_tees : & mut HashSet < * const RefCell < HfPlusNode < 'a > > > ,) { node . transform_children (| n , s | persist_pullup_node (n , s , persist_pulled_tees) , seen_tees ,) ; match node { HfPlusNode :: Unpersist (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Unpersist (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Delta (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Delta (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Tee { inner } => { if persist_pulled_tees . contains (& (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >)) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } else { let inner_borrow = inner . borrow () ; if let HfPlusNode :: Persist (_) = inner_borrow . deref () { drop (inner_borrow) ; persist_pulled_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >) ; if let HfPlusNode :: Persist (box behind_persist) = inner . replace (HfPlusNode :: Placeholder) { * inner . borrow_mut () = behind_persist ; } else { unreachable ! () } * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } } } HfPlusNode :: Map { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Map { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Map { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: FlatMap { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: FlatMap { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: FlatMap { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Filter { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Filter { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Filter { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Network { input : box HfPlusNode :: Persist (_) , .. } => { if let HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Union (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Union (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Union (left , right))) ; } else { unreachable ! () } } HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: CrossProduct (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,) ,)))) ; } else { unreachable ! () } } HfPlusNode :: Join (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Join (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: Join (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,))))) ; } else { unreachable ! () } } _ => { } } } pub fn persist_pullup (ir : Vec < HfPlusLeaf >) -> Vec < HfPlusLeaf > { let mut seen_tees = Default :: default () ; let mut persist_pulled_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| n , s | persist_pullup_node (n , s , & mut persist_pulled_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn persist_pullup_through_map () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } # [test] fn persist_pullup_behind_tee () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; let before_tee = flow . source_iter (& process , q ! (0 .. 10)) . tick_batch () . persist () ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } } } pub mod profiler { pub use std :: cell :: RefCell ; pub use hydroflow :: futures :: channel :: mpsc :: UnboundedSender ; pub use stageleft :: * ; pub use crate as hydroflow_plus ; pub use crate :: ir :: * ; pub use crate :: RuntimeContext ; pub fn increment_counter (count : & mut u64) { * count += 1 ; } pub fn quoted_any_fn < 'a , F : Fn (& usize) + 'a , Q : IntoQuotedMut < 'a , F > > (q : Q) -> Q { q } # [doc = " Add a profiling node before each node to count the cardinality of its input"] pub fn add_profiling_node < 'a > (node : & mut HfPlusNode < 'a > , _context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > , id : & mut u32 , seen_tees : & mut SeenTees < 'a > ,) { let my_id = * id ; * id += 1 ; node . transform_children (| node , seen_tees | { add_profiling_node (node , _context , counters , counter_queue , id , seen_tees) } , seen_tees ,) ; let orig_node = std :: mem :: replace (node , HfPlusNode :: Placeholder) ; * node = HfPlusNode :: Inspect { f : quoted_any_fn (q ! ({ counter_queue . borrow () . unbounded_send ((my_id as usize , counters . borrow () [my_id as usize])) . unwrap () ; counters . borrow_mut () [my_id as usize] = 0 ; move | _ | { hydroflow_plus :: profiler :: increment_counter (& mut counters . borrow_mut () [my_id as usize] ,) ; } })) . splice () . into () , input : Box :: new (orig_node) , } } # [doc = " Count the cardinality of each input and periodically output to a file"] pub fn profiling < 'a > (ir : Vec < HfPlusLeaf < 'a > > , context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > ,) -> Vec < HfPlusLeaf < 'a > > { let mut id = 0 ; let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | { add_profiling_node (node , context , counters , counter_queue , & mut id , seen_tees) } , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn profiler_wrapping_all_operators () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let runtime_context = flow . runtime_context () ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (& built . ir ()) ; let counters = RuntimeData :: new ("Fake") ; let counter_queue = RuntimeData :: new ("Fake") ; let pushed_down = built . with_default_optimize () . optimize_with (| ir | super :: profiling (ir , runtime_context , counters , counter_queue)) ; insta :: assert_debug_snapshot ! (& pushed_down . ir ()) ; let _ = pushed_down . compile_no_network :: < MultiGraph > () ; } } } pub mod properties { pub use std :: collections :: HashSet ; pub use stageleft :: * ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , SeenTees } ; pub use crate :: properties :: PropertyDatabase ; # [doc = " Allows us to convert the hydroflow datatype for folds to a binary operation for the algebra"] # [doc = " property tests."] # [allow (dead_code)] pub fn convert_hf_to_binary < I , A : Default , F : Fn (& mut A , I) > (f : F) -> impl Fn (I , I) -> A { move | a , b | { let mut acc = Default :: default () ; f (& mut acc , a) ; f (& mut acc , b) ; acc } } # [cfg (stageleft_macro)] impl PropertyDatabase { # [doc = " Tags the expression as commutative."] pub fn add_commutative_tag < 'a , I , A , F : Fn (& mut A , I) , Q : Quoted < 'a , F > + Clone > (& mut self , expr : Q ,) -> Q { let expr_clone = expr . clone () ; self . commutative . insert (expr_clone . splice ()) ; expr } pub fn is_tagged_commutative (& self , expr : & syn :: Expr) -> bool { self . commutative . contains (expr) } } pub fn properties_optimize_node < 'a > (node : & mut HfPlusNode < 'a > , db : & PropertyDatabase , seen_tees : & mut SeenTees < 'a > ,) { node . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , seen_tees ,) ; match node { HfPlusNode :: ReduceKeyed { f , .. } if db . is_tagged_commutative (& f . 0) => { dbg ! ("IDENTIFIED COMMUTATIVE OPTIMIZATION for {:?}" , & f) ; } _ => { } } } pub fn properties_optimize < 'a > (ir : Vec < HfPlusLeaf < 'a > > , db : & PropertyDatabase ,) -> Vec < HfPlusLeaf < 'a > > { let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use super :: * ; use crate :: deploy :: SingleProcessGraph ; use crate :: FlowBuilder ; # [test] fn test_property_database () { let mut db = PropertyDatabase :: default () ; assert ! (! db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; let _ = db . add_commutative_tag (q ! (| a : & mut i32 , b : i32 | * a += b)) ; assert ! (db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; } # [test] fn test_property_optimized () { let flow = FlowBuilder :: new () ; let mut database = PropertyDatabase :: default () ; let process = flow . process :: < () > () ; let counter_func = q ! (| count : & mut i32 , _ | * count += 1) ; let _ = database . add_commutative_tag (counter_func) ; flow . source_iter (& process , q ! (vec ! [])) . map (q ! (| string : String | (string , ()))) . tick_batch () . fold_keyed (q ! (|| 0) , counter_func) . all_ticks () . for_each (q ! (| (string , count) | println ! ("{}: {}" , string , count))) ; let built = flow . finalize () . optimize_with (| ir | properties_optimize (ir , & database)) . with_default_optimize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let _ = built . compile_no_network :: < SingleProcessGraph > () ; } } } pub use crate :: RuntimeContext ; # [cfg (stageleft_macro)] impl Copy for RuntimeContext < '_ > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Context > for RuntimeContext < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (quote ! (& context))) } } pub use crate :: HfCompiled ; # [cfg (stageleft_macro)] impl < 'a , ID > HfCompiled < 'a , ID > { pub fn hydroflow_ir (& self) -> & BTreeMap < usize , HydroflowGraph > { & self . hydroflow_ir } } # [cfg (stageleft_macro)] impl < 'a > HfCompiled < 'a , usize > { pub fn with_dynamic_id (self , id : impl Quoted < 'a , usize >) -> HfBuiltWithId < 'a > { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; let mut conditioned_tokens = None ; for (subgraph_id , flat_graph) in self . hydroflow_ir { let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; let my_extra_stmts = self . extra_stmts . get (& subgraph_id) . cloned () . unwrap_or_default () ; if let Some (conditioned_tokens) = conditioned_tokens . as_mut () { * conditioned_tokens = syn :: parse_quote ! { # conditioned_tokens else if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } } ; } else { conditioned_tokens = Some (syn :: parse_quote ! { if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } }) ; } } let conditioned_tokens : TokenStream = conditioned_tokens . unwrap () ; let id = id . splice () ; HfBuiltWithId { tokens : syn :: parse_quote ! ({ let __given_id = # id ; # conditioned_tokens else { panic ! ("Invalid node id: {}" , __given_id) ; } }) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfCompiled < 'a , () > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfCompiled < 'a , () > { fn to_tokens (mut self) -> (Option < TokenStream > , Option < TokenStream >) { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; if self . hydroflow_ir . len () != 1 { panic ! ("Expected exactly one subgraph in the Hydroflow IR") ; } let flat_graph = self . hydroflow_ir . remove (& 0) . unwrap () ; let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; (None , Some (tokens)) } } pub use crate :: HfBuiltWithId ; # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfBuiltWithId < 'a > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfBuiltWithId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (self . tokens)) } }
[INFO] [stdout] 1 + pub use std :: collections :: BTreeMap ; pub use std :: marker :: PhantomData ; pub use hydroflow :: scheduled :: context :: Context ; pub use hydroflow :: scheduled :: graph :: Hydroflow ; pub use hydroflow :: * ; pub use lang :: graph :: { partition_graph , HydroflowGraph } ; pub use proc_macro2 :: TokenStream ; pub use quote :: quote ; pub use stageleft :: runtime_support :: FreeVariable ; pub use stageleft :: Quoted ; pub mod runtime_support { pub use bincode ; } pub mod stream { pub use std :: cell :: RefCell ; pub use std :: hash :: Hash ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow :: bytes :: Bytes ; pub use hydroflow :: futures :: Sink ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: quote ; pub use serde :: de :: DeserializeOwned ; pub use serde :: Serialize ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use syn :: parse_quote ; pub use crate :: builder :: { ClusterIds , FlowLeaves } ; pub use crate :: cycle :: { CycleCollection , CycleComplete } ; pub use crate :: ir :: { DebugInstantiate , HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { CanSend , Location , LocationId } ; pub use crate :: { Cluster , Optional , Singleton } ; pub use crate :: stream :: Unbounded ; pub use crate :: stream :: Bounded ; pub use crate :: stream :: NoTick ; pub use crate :: stream :: Tick ; pub use crate :: stream :: Stream ; # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Stream { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Stream < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Stream { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , C , N > > ,) -> Stream < 'a , (T , O) , W , C , N > where O : Clone , { let other : Optional < 'a , O , Bounded , C , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn cross_product < O > (self , other : Stream < 'a , O , W , C , N >) -> Stream < 'a , (T , O) , W , C , N > where T : Clone , O : Clone , { if self . location_kind != other . location_kind { panic ! ("cross_product must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossProduct (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn union (self , other : Stream < 'a , T , W , C , N >) -> Stream < 'a , T , W , C , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn dest_sink < S : Unpin + Sink < T > + 'a > (self , sink : impl Quoted < 'a , S >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: DestSink { sink : sink . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn first (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } # [doc = " Allow this stream through if the other stream has elements, otherwise the output is empty."] pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } # [doc = " Allow this stream through if the other stream is empty, otherwise the output is empty."] pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn enumerate (self) -> Stream < 'a , (usize , T) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Enumerate (Box :: new (self . ir_node . into_inner ())) ,) } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn sort (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Ord , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Sort (Box :: new (self . ir_node . into_inner ())) ,) } pub fn count (self) -> Singleton < 'a , usize , Bounded , Tick , N > { self . fold (q ! (|| 0usize) , q ! (| count , _ | * count += 1)) } pub fn delta (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } pub fn unique (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Eq + Hash , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unique (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn tick_batch (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_prefix (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { self . tick_batch () . persist () } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn for_each < F : Fn (T) + 'a > (self , f : impl IntoQuotedMut < 'a , F >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: ForEach { input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , f : f . splice () . into () , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Unbounded , NoTick , N > { pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . tick_batch () . continue_if (samples . first ()) . all_ticks () } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Unbounded , NoTick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , C , N : Location > Stream < 'a , T , Bounded , C , N > { pub fn filter_not_in (self , other : Stream < 'a , T , Bounded , C , N >) -> Stream < 'a , T , Bounded , C , N > where T : Eq + Hash , { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Difference (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Stream < 'a , & T , W , C , N > { pub fn cloned (self) -> Stream < 'a , T , W , C , N > { self . map (q ! (| d | d . clone ())) } } # [cfg (stageleft_macro)] impl < 'a , K , V1 , W , C , N : Location > Stream < 'a , (K , V1) , W , C , N > { pub fn join < W2 , V2 > (self , n : Stream < 'a , (K , V2) , W2 , C , N > ,) -> Stream < 'a , (K , (V1 , V2)) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Join (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } pub fn anti_join < W2 > (self , n : Stream < 'a , K , W2 , C , N >) -> Stream < 'a , (K , V1) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("anti_join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: AntiJoin (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , K : Eq + Hash , V , N : Location > Stream < 'a , (K , V) , Bounded , Tick , N > { pub fn fold_keyed < A , I : Fn () -> A + 'a , F : Fn (& mut A , V) + 'a > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , A) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FoldKeyed { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce_keyed < F : Fn (& mut V , V) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , V) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: ReduceKeyed { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } pub fn get_this_crate () -> TokenStream { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , Span :: call_site ()) ; quote ! { # ident } } } } pub fn serialize_bincode < T : Serialize > (is_demux : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if is_demux { parse_quote ! { map (| (id , data) | { (id , # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into ()) }) } } else { parse_quote ! { map (| data | { # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into () }) } } } pub fn deserialize_bincode < T : DeserializeOwned > (tagged : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if tagged { parse_quote ! { map (| res | { let (id , b) = res . unwrap () ; (id , # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& b) . unwrap ()) }) } } else { parse_quote ! { map (| res | { # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& res . unwrap ()) . unwrap () }) } } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn send_bincode < N2 : Location , CoreType > (self , other : & N2 ,) -> Stream < 'a , N :: Out < CoreType > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T > , CoreType : Serialize + DeserializeOwned , { let serialize_pipeline = Some (serialize_bincode :: < CoreType > (N :: is_demux ())) ; let deserialize_pipeline = Some (deserialize_bincode :: < CoreType > (N :: is_tagged ())) ; Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bytes < N2 : Location > (self , other : & N2 ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T > , { Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline : None , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline : if N :: is_tagged () { Some (parse_quote ! (map (| (id , b) | (id , b . unwrap () . freeze ())))) } else { Some (parse_quote ! (map (| b | b . unwrap () . freeze ()))) } , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bincode_interleaved < N2 : Location , Tag , CoreType > (self , other : & N2 ,) -> Stream < 'a , CoreType , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T , Out < CoreType > = (Tag , CoreType) > , CoreType : Serialize + DeserializeOwned , { self . send_bincode :: < N2 , CoreType > (other) . map (q ! (| (_ , b) | b)) } pub fn send_bytes_interleaved < N2 : Location , Tag > (self , other : & N2 ,) -> Stream < 'a , Bytes , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T , Out < Bytes > = (Tag , Bytes) > , { self . send_bytes :: < N2 > (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bincode < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < T > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) > , T : Clone + Serialize + DeserializeOwned , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bincode (other) } pub fn broadcast_bincode_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , T , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) , Out < T > = (Tag , T) > + 'a , T : Clone + Serialize + DeserializeOwned , { self . broadcast_bincode (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bytes < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) > + 'a , T : Clone , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bytes (other) } pub fn broadcast_bytes_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , Bytes , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) , Out < Bytes > = (Tag , Bytes) > + 'a , T : Clone , { self . broadcast_bytes (other) . map (q ! (| (_ , b) | b)) } } } pub use stream :: { Bounded , NoTick , Stream , Tick , Unbounded } ; pub mod singleton { pub use std :: cell :: RefCell ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use crate :: builder :: FlowLeaves ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial , CycleComplete } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: Stream ; pub use crate :: singleton :: CrossResult ; # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Singleton < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Singleton :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } pub use crate :: singleton :: Singleton ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Singleton { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleComplete < 'a > for Singleton < 'a , T , Bounded , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleCollectionWithInitial < 'a > for Singleton < 'a , T , Bounded , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , initial : Self , l : LocationId ,) -> Self { Singleton :: new (l , ir_leaves , HfPlusNode :: Union (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , }) , initial . ir_node . into_inner () . into () ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Singleton < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Singleton { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , U , W , C , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (Self :: other_ir_node (other)) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Singleton < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CrossSingleton (Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , Box :: new (HfPlusNode :: Unpersist (Box :: new (Self :: other_ir_node (other)))) ,))) ,) } } pub use crate :: singleton :: Optional ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Optional { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } pub fn some (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: new (singleton . location_kind , singleton . ir_leaves , singleton . ir_node . into_inner () ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > From < Singleton < 'a , T , W , C , N > > for Optional < 'a , T , W , C , N > { fn from (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: some (singleton) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Optional < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Optional { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn into_stream (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , Tick , N > > ,) -> Optional < 'a , (T , O) , Bounded , Tick , N > where O : Clone , { let other : Optional < 'a , O , Bounded , Tick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn union (self , other : Optional < 'a , T , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Optional < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_samples (self) -> Stream < 'a , T , Unbounded , NoTick , N > { self . latest_tick () . all_ticks () } pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . latest_tick () . continue_if (samples . first ()) . latest () . tick_samples () } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Unbounded , NoTick , N > > ,) -> Optional < 'a , (T , O) , Unbounded , NoTick , N > where O : Clone , { let other : Optional < 'a , O , Unbounded , NoTick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } self . latest_tick () . cross_singleton (other . latest_tick ()) . latest () } } } pub use singleton :: { Optional , Singleton } ; pub mod location { pub use std :: marker :: PhantomData ; pub use crate :: location :: LocationId ; pub use crate :: location :: Location ; pub use crate :: location :: Process ; # [cfg (stageleft_macro)] impl < P > Clone for Process < P > { fn clone (& self) -> Self { Process { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < P > Location for Process < P > { fn id (& self) -> LocationId { LocationId :: Process (self . id) } } pub use crate :: location :: Cluster ; # [cfg (stageleft_macro)] impl < C > Clone for Cluster < C > { fn clone (& self) -> Self { Cluster { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < C > Location for Cluster < C > { fn id (& self) -> LocationId { LocationId :: Cluster (self . id) } } pub use crate :: location :: CanSend ; # [cfg (stageleft_macro)] impl < P1 , P2 > CanSend < Process < P2 > > for Process < P1 > { type In < T > = T ; type Out < T > = T ; fn is_demux () -> bool { false } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < P1 , C2 > CanSend < Cluster < C2 > > for Process < P1 > { type In < T > = (u32 , T) ; type Out < T > = T ; fn is_demux () -> bool { true } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < C1 , P2 > CanSend < Process < P2 > > for Cluster < C1 > { type In < T > = T ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { false } fn is_tagged () -> bool { true } } # [cfg (stageleft_macro)] impl < C1 , C2 > CanSend < Cluster < C2 > > for Cluster < C1 > { type In < T > = (u32 , T) ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { true } fn is_tagged () -> bool { true } } } pub use location :: { Cluster , Process } ; pub mod deploy { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use stageleft :: Quoted ; pub mod graphs { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use super :: { LocalDeploy , Node , ProcessSpec } ; pub use crate :: deploy :: graphs :: SingleProcessGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for SingleProcessGraph { type Process = SingleNode ; type Cluster = SingleNode ; type Meta = () ; type GraphId = () ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { SingleNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { SingleNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , SingleProcessGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> SingleNode { SingleNode { } } } pub use crate :: deploy :: graphs :: SingleNode ; # [cfg (stageleft_macro)] impl Node for SingleNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } pub use crate :: deploy :: graphs :: MultiGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for MultiGraph { type Process = MultiNode ; type Cluster = MultiNode ; type Meta = () ; type GraphId = usize ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { MultiNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { MultiNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , MultiGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> MultiNode { MultiNode { } } } pub use crate :: deploy :: graphs :: MultiNode ; # [cfg (stageleft_macro)] impl Node for MultiNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } } pub use graphs :: * ; pub use crate :: deploy :: LocalDeploy ; pub use crate :: deploy :: Deploy ; # [cfg (stageleft_macro)] impl < 'a , T : Deploy < 'a , Process = N , Cluster = C , Meta = M , GraphId = R > , N : Node < Meta = M > , C : Node < Meta = M > , M : Default , R , > LocalDeploy < 'a > for T { type Process = N ; type Cluster = C ; type Meta = M ; type GraphId = R ; fn has_trivial_node () -> bool { < T as Deploy < 'a > > :: has_trivial_node () } fn trivial_process (id : usize) -> Self :: Process { < T as Deploy < 'a > > :: trivial_process (id) } fn trivial_cluster (id : usize) -> Self :: Cluster { < T as Deploy < 'a > > :: trivail_cluster (id) } } pub use crate :: deploy :: ProcessSpec ; pub use crate :: deploy :: ClusterSpec ; pub use crate :: deploy :: Node ; } pub use deploy :: { ClusterSpec , Deploy , ProcessSpec } ; pub mod cycle { pub use std :: marker :: PhantomData ; pub use crate :: builder :: FlowLeaves ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: cycle :: CycleComplete ; pub use crate :: cycle :: CycleCollection ; pub use crate :: cycle :: CycleCollectionWithInitial ; pub use crate :: cycle :: HfCycle ; # [cfg (stageleft_macro)] impl < 'a , S : CycleComplete < 'a > > HfCycle < 'a , S > { pub fn complete (self , stream : S) { let ident = self . ident ; S :: complete (stream , ident) } } } pub use cycle :: HfCycle ; pub mod builder { pub use std :: cell :: RefCell ; pub use std :: collections :: HashMap ; pub use std :: marker :: PhantomData ; pub use std :: rc :: Rc ; pub use std :: time :: Duration ; pub use hydroflow :: futures :: stream :: Stream as FuturesStream ; pub use hydroflow :: { tokio , tokio_stream } ; pub use internal :: TokenStream ; pub use proc_macro2 :: Span ; pub use quote :: quote ; pub use runtime_support :: FreeVariable ; pub use stageleft :: * ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Cluster , Location , LocationId , Process } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: { HfCycle , Optional , RuntimeContext , Singleton , Stream } ; pub mod built { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use hydroflow_lang :: graph :: { eliminate_extra_unions_tees , HydroflowGraph } ; pub use super :: deploy :: { DeployFlow , DeployResult } ; pub use crate :: deploy :: { ClusterSpec , Deploy , LocalDeploy , ProcessSpec } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Cluster , Process } ; pub use crate :: HfCompiled ; pub use crate :: builder :: built :: BuiltFlow ; # [cfg (stageleft_macro)] impl < 'a > Drop for BuiltFlow < 'a > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped BuiltFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn ir (& self) -> & Vec < HfPlusLeaf < 'a > > { & self . ir } pub fn optimize_with (mut self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> BuiltFlow < 'a > { self . used = true ; BuiltFlow { ir : f (std :: mem :: take (& mut self . ir)) , processes : std :: mem :: take (& mut self . processes) , clusters : std :: mem :: take (& mut self . clusters) , used : false , _phantom : PhantomData , } } } pub fn build_inner (ir : & mut Vec < HfPlusLeaf >) -> BTreeMap < usize , HydroflowGraph > { let mut builders = BTreeMap :: new () ; let mut built_tees = HashMap :: new () ; let mut next_stmt_id = 0 ; for leaf in ir { leaf . emit (& mut builders , & mut built_tees , & mut next_stmt_id) ; } builders . into_iter () . map (| (k , v) | { let (mut flat_graph , _ , _) = v . build () ; eliminate_extra_unions_tees (& mut flat_graph) ; (k , flat_graph) }) . collect () } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn compile_no_network < D : LocalDeploy < 'a > > (mut self) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; HfCompiled { hydroflow_ir : build_inner (& mut self . ir) , extra_stmts : BTreeMap :: new () , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> BuiltFlow < 'a > { self . optimize_with (crate :: persist_pullup :: persist_pullup) } fn into_deploy < D : LocalDeploy < 'a > > (mut self) -> DeployFlow < 'a , D > { self . used = true ; let processes = if D :: has_trivial_node () { self . processes . iter () . map (| id | (* id , D :: trivial_process (* id))) . collect () } else { HashMap :: new () } ; let clusters = if D :: has_trivial_node () { self . clusters . iter () . map (| id | (* id , D :: trivial_cluster (* id))) . collect () } else { HashMap :: new () } ; DeployFlow { ir : std :: mem :: take (& mut self . ir) , nodes : processes , clusters , used : false , _phantom : PhantomData , } } pub fn with_process < P , D : LocalDeploy < 'a > > (self , process : & Process < P > , spec : impl ProcessSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_process (process , spec) } pub fn with_cluster < C , D : LocalDeploy < 'a > > (self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_cluster (cluster , spec) } pub fn compile < D : Deploy < 'a > + 'a > (self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . into_deploy :: < D > () . compile (env) } pub fn deploy < D : Deploy < 'a , CompileEnv = () > + 'a > (self , env : & mut D :: InstantiateEnv ,) -> DeployResult < 'a , D > { self . into_deploy :: < D > () . deploy (env) } } } pub mod deploy { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use proc_macro2 :: Span ; pub use stageleft :: Quoted ; pub use super :: built :: build_inner ; pub use crate :: deploy :: { LocalDeploy , Node } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: { Cluster , ClusterSpec , Deploy , HfCompiled , Process , ProcessSpec } ; pub use crate :: builder :: deploy :: DeployFlow ; # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > Drop for DeployFlow < 'a , D > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped DeployFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > DeployFlow < 'a , D > { pub fn with_process < P > (mut self , process : & Process < P > , spec : impl ProcessSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < P > () . to_string () ; self . nodes . insert (process . id , spec . build (process . id , & tag_name)) ; self } pub fn with_cluster < C > (mut self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < C > () . to_string () ; self . clusters . insert (cluster . id , spec . build (cluster . id , & tag_name)) ; self } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployFlow < 'a , D > { pub fn compile (mut self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; let mut seen_tees : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | leaf . compile_network :: < D > (env , & mut seen_tees , & self . nodes , & self . clusters)) . collect () ; let extra_stmts = self . extra_stmts (env) ; HfCompiled { hydroflow_ir : build_inner (& mut ir_leaves_networked) , extra_stmts , _phantom : PhantomData , } } fn extra_stmts (& self , env : & < D as Deploy < 'a > > :: CompileEnv) -> BTreeMap < usize , Vec < syn :: Stmt > > { let all_locations_count = self . nodes . len () + self . clusters . len () ; let mut extra_stmts : BTreeMap < usize , Vec < syn :: Stmt > > = BTreeMap :: new () ; for & c_id in self . clusters . keys () { let self_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , c_id) , Span :: call_site () ,) ; let self_id_expr = D :: cluster_self_id (env) . splice () ; extra_stmts . entry (c_id) . or_default () . push (syn :: parse_quote ! { let # self_id_ident = # self_id_expr ; }) ; for other_location in 0 .. all_locations_count { let other_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , c_id) , Span :: call_site () ,) ; let other_id_expr = D :: cluster_ids (env , c_id) . splice () ; extra_stmts . entry (other_location) . or_default () . push (syn :: parse_quote ! { let # other_id_ident = # other_id_expr ; }) ; } } extra_stmts } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a , CompileEnv = () > > DeployFlow < 'a , D > { # [must_use] pub fn deploy (mut self , env : & mut D :: InstantiateEnv) -> DeployResult < 'a , D > { self . used = true ; let mut seen_tees_instantiate : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | { leaf . compile_network :: < D > (& () , & mut seen_tees_instantiate , & self . nodes , & self . clusters ,) }) . collect () ; let mut compiled = build_inner (& mut ir_leaves_networked) ; let mut extra_stmts = self . extra_stmts (& ()) ; let mut meta = D :: Meta :: default () ; let (mut processes , mut clusters) = (std :: mem :: take (& mut self . nodes) . into_iter () . map (| (node_id , node) | { node . instantiate (env , & mut meta , compiled . remove (& node_id) . unwrap () , extra_stmts . remove (& node_id) . unwrap_or_default () ,) ; (node_id , node) }) . collect :: < HashMap < _ , _ > > () , std :: mem :: take (& mut self . clusters) . into_iter () . map (| (cluster_id , cluster) | { cluster . instantiate (env , & mut meta , compiled . remove (& cluster_id) . unwrap () , extra_stmts . remove (& cluster_id) . unwrap_or_default () ,) ; (cluster_id , cluster) }) . collect :: < HashMap < _ , _ > > () ,) ; for node in processes . values_mut () { node . update_meta (& meta) ; } for cluster in clusters . values_mut () { cluster . update_meta (& meta) ; } let mut seen_tees_connect = HashMap :: new () ; for leaf in ir_leaves_networked { leaf . connect_network (& mut seen_tees_connect) ; } DeployResult { processes , clusters , } } } pub use crate :: builder :: deploy :: DeployResult ; # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployResult < 'a , D > { pub fn get_process < P > (& self , p : & Process < P >) -> & D :: Process { let id = match p . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . processes . get (& id) . unwrap () } pub fn get_cluster < C > (& self , c : & Cluster < C >) -> & D :: Cluster { let id = match c . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . clusters . get (& id) . unwrap () } } } # [doc = " Tracks the leaves of the dataflow IR. This is referenced by"] # [doc = " `Stream` and `HfCycle` to build the IR. The inner option will"] # [doc = " be set to `None` when this builder is finalized."] pub type FlowLeaves < 'a > = Rc < RefCell < Option < Vec < HfPlusLeaf < 'a > > > > > ; pub use crate :: builder :: ClusterIds ; # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Vec < u32 > > for ClusterIds < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , & 'a Vec < u32 > > for ClusterIds < 'a > { } # [derive (Copy , Clone)] pub struct ClusterSelfId < 'a > { pub id : usize , pub _phantom : PhantomData < & 'a mut & 'a u32 > , } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < u32 > for ClusterSelfId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , u32 > for ClusterSelfId < 'a > { } pub use crate :: builder :: FlowBuilder ; # [cfg (stageleft_macro)] impl < 'a > Drop for FlowBuilder < 'a > { fn drop (& mut self) { if ! self . finalized { panic ! ("Dropped FlowBuilder without finalizing, you may have forgotten to call `with_default_optimize`, `optimize_with`, or `finalize`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > QuotedContext for FlowBuilder < 'a > { fn create () -> Self { FlowBuilder :: new () } } # [cfg (stageleft_macro)] impl < 'a > FlowBuilder < 'a > { # [allow (clippy :: new_without_default)] pub fn new () -> FlowBuilder < 'a > { FlowBuilder { ir_leaves : Rc :: new (RefCell :: new (Some (Vec :: new ()))) , nodes : RefCell :: new (vec ! []) , clusters : RefCell :: new (vec ! []) , cycle_ids : RefCell :: new (HashMap :: new ()) , next_node_id : RefCell :: new (0) , finalized : false , _phantom : PhantomData , } } pub fn finalize (mut self) -> built :: BuiltFlow < 'a > { self . finalized = true ; built :: BuiltFlow { ir : self . ir_leaves . borrow_mut () . take () . unwrap () , processes : self . nodes . replace (vec ! []) , clusters : self . clusters . replace (vec ! []) , used : false , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> built :: BuiltFlow < 'a > { self . finalize () . with_default_optimize () } pub fn optimize_with (self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> built :: BuiltFlow < 'a > { self . finalize () . optimize_with (f) } pub fn ir_leaves (& self) -> & FlowLeaves < 'a > { & self . ir_leaves } pub fn process < P > (& self) -> Process < P > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . nodes . borrow_mut () . push (id) ; Process { id , _phantom : PhantomData , } } pub fn cluster < C > (& self) -> Cluster < C > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . clusters . borrow_mut () . push (id) ; Cluster { id , _phantom : PhantomData , } } pub fn runtime_context (& self) -> RuntimeContext < 'a > { RuntimeContext { _phantom : PhantomData , } } pub fn cluster_members < C > (& self , cluster : & Cluster < C > ,) -> impl Quoted < 'a , & 'a Vec < u32 > > + Copy + 'a { ClusterIds { id : cluster . id , _phantom : PhantomData , } } pub fn cluster_self_id < C > (& self , cluster : & Cluster < C >) -> impl Quoted < 'a , u32 > + Copy + 'a { ClusterSelfId { id : cluster . id , _phantom : PhantomData , } } pub fn spin < L : Location > (& self , on : & L) -> Stream < 'a , () , Unbounded , NoTick , L > { Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Spin () , location_kind : on . id () , })) ,) } pub fn spin_batch < L : Location > (& self , on : & L , batch_size : impl Quoted < 'a , usize > + Copy + 'a ,) -> Stream < 'a , () , Bounded , Tick , L > { self . spin (on) . flat_map (q ! (move | _ | 0 .. batch_size)) . map (q ! (| _ | ())) . tick_batch () } pub fn source_stream < T , E : FuturesStream < Item = T > + Unpin , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Unbounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Stream (e . into ()) , location_kind : on . id () , })) ,) } pub fn source_iter < T , E : IntoIterator < Item = T > , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Bounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , })) ,) } pub fn singleton < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Singleton < 'a , T , Bounded , NoTick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Singleton :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,)))) ,) } pub fn singleton_first_tick < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Optional < 'a , T , Bounded , Tick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,) } pub fn source_interval < L : Location > (& self , on : & L , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , () , Unbounded , NoTick , L > { let interval = interval . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : on . id () , })) ,) } pub fn source_interval_delayed < L : Location > (& self , on : & L , delay : impl Quoted < 'a , Duration > + Copy + 'a , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , tokio :: time :: Instant , Unbounded , NoTick , L > { self . source_stream (on , q ! (tokio_stream :: wrappers :: IntervalStream :: new (tokio :: time :: interval_at (tokio :: time :: Instant :: now () + delay , interval))) ,) . tick_batch () . first () . latest () } pub fn cycle < S : CycleCollection < 'a > > (& self , on : & S :: Location) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , on . id ()) ,) } pub fn cycle_with_initial < S : CycleCollectionWithInitial < 'a > > (& self , on : & S :: Location , initial : S ,) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , initial , on . id ()) ,) } } } pub use builder :: FlowBuilder ; pub mod ir { pub use core :: panic ; pub use std :: cell :: RefCell ; pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow_lang :: graph :: FlatGraphBuilder ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: ToTokens ; pub use syn :: parse_quote ; pub use crate :: deploy :: Deploy ; pub use crate :: location :: LocationId ; pub use crate :: ir :: DebugExpr ; # [cfg (stageleft_macro)] impl From < syn :: Expr > for DebugExpr { fn from (expr : syn :: Expr) -> DebugExpr { DebugExpr (expr) } } # [cfg (stageleft_macro)] impl Deref for DebugExpr { type Target = syn :: Expr ; fn deref (& self) -> & Self :: Target { & self . 0 } } # [cfg (stageleft_macro)] impl ToTokens for DebugExpr { fn to_tokens (& self , tokens : & mut TokenStream) { self . 0 . to_tokens (tokens) ; } } # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugExpr { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "{}" , self . 0 . to_token_stream ()) } } pub use crate :: ir :: DebugInstantiate ; # [cfg (stageleft_macro)] impl < 'a > std :: fmt :: Debug for DebugInstantiate < 'a > { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<network instantiate>") } } pub use crate :: ir :: DebugPipelineFn ; # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugPipelineFn { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<function>") } } pub use crate :: ir :: HfPlusSource ; pub use crate :: ir :: HfPlusLeaf ; # [cfg (stageleft_macro)] impl < 'a > HfPlusLeaf < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . compile_network :: < D > (compile_env , s , nodes , clusters) ; } , seen_tees ,) } pub fn connect_network (self , seen_tees : & mut SeenTees < 'a >) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . connect_network (s) ; } , seen_tees ,) } pub fn transform_children (self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) -> HfPlusLeaf < 'a > { match self { HfPlusLeaf :: ForEach { f , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: ForEach { f , input } } HfPlusLeaf :: DestSink { sink , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: DestSink { sink , input } } HfPlusLeaf :: CycleSink { ident , location_kind , mut input , } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: CycleSink { ident , location_kind , input , } } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) { match self { HfPlusLeaf :: ForEach { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> for_each (# f) ; }) ; } HfPlusLeaf :: DestSink { sink , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink) ; }) ; } HfPlusLeaf :: CycleSink { ident , location_kind , input , } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; assert_eq ! (input_location_id , * location_id , "cycle_sink location mismatch") ; graph_builders . entry (* location_id) . or_default () . add_statement (parse_quote ! { # ident = # input_ident ; }) ; } } } } pub use crate :: ir :: HfPlusNode ; pub type SeenTees < 'a > = HashMap < * const RefCell < HfPlusNode < 'a > > , Rc < RefCell < HfPlusNode < 'a > > > > ; # [cfg (stageleft_macro)] impl < 'a > HfPlusNode < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (& mut self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) { self . transform_children (| n , s | n . compile_network :: < D > (compile_env , s , nodes , clusters) , seen_tees ,) ; if let HfPlusNode :: Network { from_location , to_location , instantiate_fn , .. } = self { let (sink_expr , source_expr , connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { let ((sink , source) , connect_fn) = match (from_location , to_location) { (LocationId :: Process (from) , LocationId :: Process (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: o2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Process (from) , LocationId :: Cluster (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: o2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Process (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: m2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Cluster (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: m2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } } ; (sink , source , connect_fn) } DebugInstantiate :: Finalized (_ , _ , _) => panic ! ("network already finalized") , } ; * instantiate_fn = DebugInstantiate :: Finalized (sink_expr , source_expr , connect_fn) ; } } pub fn connect_network (& mut self , seen_tees : & mut SeenTees < 'a >) { self . transform_children (| n , s | n . connect_network (s) , seen_tees) ; if let HfPlusNode :: Network { instantiate_fn , .. } = self { match instantiate_fn { DebugInstantiate :: Building () => panic ! ("network not built") , DebugInstantiate :: Finalized (_ , _ , ref connect_fn) => { connect_fn () ; } } } } pub fn transform_children (& mut self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) { match self { HfPlusNode :: Placeholder => { panic ! () ; } HfPlusNode :: Source { .. } => { } HfPlusNode :: CycleSource { .. } => { } HfPlusNode :: Tee { inner } => { if let Some (transformed) = seen_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { * inner = transformed . clone () ; } else { let transformed_cell = Rc :: new (RefCell :: new (HfPlusNode :: Placeholder)) ; seen_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , transformed_cell . clone () ,) ; let mut orig = inner . replace (HfPlusNode :: Placeholder) ; transform (& mut orig , seen_tees) ; * transformed_cell . borrow_mut () = orig ; * inner = transformed_cell ; } } HfPlusNode :: Persist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Unpersist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Delta (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Union (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossProduct (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossSingleton (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Join (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Difference (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: AntiJoin (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Map { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FlatMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Filter { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FilterMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Sort (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: DeferTick (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Enumerate (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Inspect { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Unique (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Fold { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FoldKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Reduce { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: ReduceKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Network { input , .. } => { transform (input . as_mut () , seen_tees) ; } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) -> (syn :: Ident , usize) { match self { HfPlusNode :: Placeholder => { panic ! () } HfPlusNode :: Persist (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let persist_id = * next_stmt_id ; * next_stmt_id += 1 ; let persist_ident = syn :: Ident :: new (& format ! ("stream_{}" , persist_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # persist_ident = # inner_ident -> persist ::<'static > () ; }) ; (persist_ident , location) } HfPlusNode :: Unpersist (_) => { panic ! ("Unpersist is a marker node and should have been optimized away. This is likely a compiler bug.") } HfPlusNode :: Delta (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let delta_id = * next_stmt_id ; * next_stmt_id += 1 ; let delta_ident = syn :: Ident :: new (& format ! ("stream_{}" , delta_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # delta_ident = # inner_ident -> multiset_delta () ; }) ; (delta_ident , location) } HfPlusNode :: Source { source , location_kind , } => { let source_id = * next_stmt_id ; * next_stmt_id += 1 ; let source_ident = syn :: Ident :: new (& format ! ("stream_{}" , source_id) , Span :: call_site ()) ; let source_stmt = match source { HfPlusSource :: Stream (expr) => { parse_quote ! { # source_ident = source_stream (# expr) ; } } HfPlusSource :: Iter (expr) => { parse_quote ! { # source_ident = source_iter (# expr) ; } } HfPlusSource :: Interval (expr) => { parse_quote ! { # source_ident = source_interval (# expr) ; } } HfPlusSource :: Spin () => { parse_quote ! { # source_ident = spin () ; } } } ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; graph_builders . entry (* location_id) . or_default () . add_statement (source_stmt) ; (source_ident , * location_id) } HfPlusNode :: CycleSource { ident , location_kind , } => { let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; (ident . clone () , * location_id) } HfPlusNode :: Tee { inner } => { if let Some (ret) = built_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { ret . clone () } else { let (inner_ident , inner_location_id) = inner . borrow () . emit (graph_builders , built_tees , next_stmt_id) ; let tee_id = * next_stmt_id ; * next_stmt_id += 1 ; let tee_ident = syn :: Ident :: new (& format ! ("stream_{}" , tee_id) , Span :: call_site ()) ; let builder = graph_builders . entry (inner_location_id) . or_default () ; builder . add_statement (parse_quote ! { # tee_ident = # inner_ident -> tee () ; }) ; built_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , (tee_ident . clone () , inner_location_id) ,) ; (tee_ident , inner_location_id) } } HfPlusNode :: Union (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "union inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let union_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # union_ident = union () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [0] # union_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # union_ident ; }) ; (union_ident , left_location_id) } HfPlusNode :: CrossSingleton (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "cross_singleton inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let cross_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # cross_ident = cross_singleton () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [input] # cross_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [single] # cross_ident ; }) ; (cross_ident , left_location_id) } HfPlusNode :: CrossProduct (..) | HfPlusNode :: Join (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: CrossProduct (..)) { parse_quote ! (cross_join_multiset) } else { parse_quote ! (join_multiset) } ; let (HfPlusNode :: CrossProduct (left , right) | HfPlusNode :: Join (left , right)) = self else { unreachable ! () } ; let (left_inner , left_was_persist) = if let HfPlusNode :: Persist (left) = left . as_ref () { (left , true) } else { (left , false) } ; let (right_inner , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left_inner . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right_inner . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "join / cross product inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; match (left_was_persist , right_was_persist) { (true , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'static > () ; }) ; } (true , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'tick > () ; }) ; } (false , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } (false , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } } ; builder . add_statement (parse_quote ! { # left_ident -> [0] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Difference (..) | HfPlusNode :: AntiJoin (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Difference (..)) { parse_quote ! (difference_multiset) } else { parse_quote ! (anti_join_multiset) } ; let (HfPlusNode :: Difference (left , right) | HfPlusNode :: AntiJoin (left , right)) = self else { unreachable ! () } ; let (right , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "difference / anti join inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; if right_was_persist { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } else { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } builder . add_statement (parse_quote ! { # left_ident -> [pos] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [neg] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Map { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let map_id = * next_stmt_id ; * next_stmt_id += 1 ; let map_ident = syn :: Ident :: new (& format ! ("stream_{}" , map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # map_ident = # input_ident -> map (# f) ; }) ; (map_ident , input_location_id) } HfPlusNode :: FlatMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let flat_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let flat_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , flat_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # flat_map_ident = # input_ident -> flat_map (# f) ; }) ; (flat_map_ident , input_location_id) } HfPlusNode :: Filter { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_ident = # input_ident -> filter (# f) ; }) ; (filter_ident , input_location_id) } HfPlusNode :: FilterMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_map_ident = # input_ident -> filter_map (# f) ; }) ; (filter_map_ident , input_location_id) } HfPlusNode :: Sort (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sort_id = * next_stmt_id ; * next_stmt_id += 1 ; let sort_ident = syn :: Ident :: new (& format ! ("stream_{}" , sort_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # sort_ident = # input_ident -> sort () ; }) ; (sort_ident , input_location_id) } HfPlusNode :: DeferTick (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let defer_tick_id = * next_stmt_id ; * next_stmt_id += 1 ; let defer_tick_ident = syn :: Ident :: new (& format ! ("stream_{}" , defer_tick_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # defer_tick_ident = # input_ident -> defer_tick_lazy () ; }) ; (defer_tick_ident , input_location_id) } HfPlusNode :: Enumerate (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let enumerate_id = * next_stmt_id ; * next_stmt_id += 1 ; let enumerate_ident = syn :: Ident :: new (& format ! ("stream_{}" , enumerate_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # enumerate_ident = # input_ident -> enumerate () ; }) ; (enumerate_ident , input_location_id) } HfPlusNode :: Inspect { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let inspect_id = * next_stmt_id ; * next_stmt_id += 1 ; let inspect_ident = syn :: Ident :: new (& format ! ("stream_{}" , inspect_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # inspect_ident = # input_ident -> inspect (# f) ; }) ; (inspect_ident , input_location_id) } HfPlusNode :: Unique (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let unique_id = * next_stmt_id ; * next_stmt_id += 1 ; let unique_ident = syn :: Ident :: new (& format ! ("stream_{}" , unique_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # unique_ident = # input_ident -> unique ::<'tick > () ; }) ; (unique_ident , input_location_id) } HfPlusNode :: Fold { .. } | HfPlusNode :: FoldKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Fold { .. }) { parse_quote ! (fold) } else { parse_quote ! (fold_keyed) } ; let (HfPlusNode :: Fold { init , acc , input } | HfPlusNode :: FoldKeyed { init , acc , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let fold_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'static > (# init , # acc) ; }) ; } else { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'tick > (# init , # acc) ; }) ; } (fold_ident , input_location_id) } HfPlusNode :: Reduce { .. } | HfPlusNode :: ReduceKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Reduce { .. }) { parse_quote ! (reduce) } else { parse_quote ! (reduce_keyed) } ; let (HfPlusNode :: Reduce { f , input } | HfPlusNode :: ReduceKeyed { f , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let reduce_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'static > (# f) ; }) ; } else { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'tick > (# f) ; }) ; } (reduce_ident , input_location_id) } HfPlusNode :: Network { from_location : _ , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input , } => { let (sink_expr , source_expr , _connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { panic ! ("Expected the network to be finalized") } DebugInstantiate :: Finalized (sink , source , connect_fn) => { (sink , source , connect_fn) } } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sender_builder = graph_builders . entry (input_location_id) . or_default () ; if let Some (serialize_pipeline) = serialize_pipeline { sender_builder . add_statement (parse_quote ! { # input_ident -> # serialize_pipeline -> dest_sink (# sink_expr) ; }) ; } else { sender_builder . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink_expr) ; }) ; } let to_id = match to_location { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let receiver_builder = graph_builders . entry (* to_id) . or_default () ; let receiver_stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let receiver_stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , receiver_stream_id) , Span :: call_site ()) ; if let Some (deserialize_pipeline) = deserialize_pipeline { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) -> # deserialize_pipeline ; }) ; } else { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) ; }) ; } (receiver_stream_ident , * to_id) } } } } } pub mod persist_pullup { pub use std :: cell :: RefCell ; pub use std :: collections :: HashSet ; pub use std :: ops :: Deref ; pub use crate :: ir :: * ; pub fn persist_pullup_node < 'a > (node : & mut HfPlusNode < 'a > , seen_tees : & mut SeenTees < 'a > , persist_pulled_tees : & mut HashSet < * const RefCell < HfPlusNode < 'a > > > ,) { node . transform_children (| n , s | persist_pullup_node (n , s , persist_pulled_tees) , seen_tees ,) ; match node { HfPlusNode :: Unpersist (deref!(HfPlusNode :: Persist (_))) => { if let HfPlusNode :: Unpersist (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Delta (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Delta (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Tee { inner } => { if persist_pulled_tees . contains (& (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >)) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } else { let inner_borrow = inner . borrow () ; if let HfPlusNode :: Persist (_) = inner_borrow . deref () { drop (inner_borrow) ; persist_pulled_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >) ; if let HfPlusNode :: Persist (box behind_persist) = inner . replace (HfPlusNode :: Placeholder) { * inner . borrow_mut () = behind_persist ; } else { unreachable ! () } * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } } } HfPlusNode :: Map { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Map { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Map { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: FlatMap { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: FlatMap { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: FlatMap { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Filter { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Filter { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Filter { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Network { input : box HfPlusNode :: Persist (_) , .. } => { if let HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Union (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Union (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Union (left , right))) ; } else { unreachable ! () } } HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: CrossProduct (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,) ,)))) ; } else { unreachable ! () } } HfPlusNode :: Join (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Join (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: Join (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,))))) ; } else { unreachable ! () } } _ => { } } } pub fn persist_pullup (ir : Vec < HfPlusLeaf >) -> Vec < HfPlusLeaf > { let mut seen_tees = Default :: default () ; let mut persist_pulled_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| n , s | persist_pullup_node (n , s , & mut persist_pulled_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn persist_pullup_through_map () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } # [test] fn persist_pullup_behind_tee () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; let before_tee = flow . source_iter (& process , q ! (0 .. 10)) . tick_batch () . persist () ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } } } pub mod profiler { pub use std :: cell :: RefCell ; pub use hydroflow :: futures :: channel :: mpsc :: UnboundedSender ; pub use stageleft :: * ; pub use crate as hydroflow_plus ; pub use crate :: ir :: * ; pub use crate :: RuntimeContext ; pub fn increment_counter (count : & mut u64) { * count += 1 ; } pub fn quoted_any_fn < 'a , F : Fn (& usize) + 'a , Q : IntoQuotedMut < 'a , F > > (q : Q) -> Q { q } # [doc = " Add a profiling node before each node to count the cardinality of its input"] pub fn add_profiling_node < 'a > (node : & mut HfPlusNode < 'a > , _context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > , id : & mut u32 , seen_tees : & mut SeenTees < 'a > ,) { let my_id = * id ; * id += 1 ; node . transform_children (| node , seen_tees | { add_profiling_node (node , _context , counters , counter_queue , id , seen_tees) } , seen_tees ,) ; let orig_node = std :: mem :: replace (node , HfPlusNode :: Placeholder) ; * node = HfPlusNode :: Inspect { f : quoted_any_fn (q ! ({ counter_queue . borrow () . unbounded_send ((my_id as usize , counters . borrow () [my_id as usize])) . unwrap () ; counters . borrow_mut () [my_id as usize] = 0 ; move | _ | { hydroflow_plus :: profiler :: increment_counter (& mut counters . borrow_mut () [my_id as usize] ,) ; } })) . splice () . into () , input : Box :: new (orig_node) , } } # [doc = " Count the cardinality of each input and periodically output to a file"] pub fn profiling < 'a > (ir : Vec < HfPlusLeaf < 'a > > , context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > ,) -> Vec < HfPlusLeaf < 'a > > { let mut id = 0 ; let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | { add_profiling_node (node , context , counters , counter_queue , & mut id , seen_tees) } , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn profiler_wrapping_all_operators () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let runtime_context = flow . runtime_context () ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (& built . ir ()) ; let counters = RuntimeData :: new ("Fake") ; let counter_queue = RuntimeData :: new ("Fake") ; let pushed_down = built . with_default_optimize () . optimize_with (| ir | super :: profiling (ir , runtime_context , counters , counter_queue)) ; insta :: assert_debug_snapshot ! (& pushed_down . ir ()) ; let _ = pushed_down . compile_no_network :: < MultiGraph > () ; } } } pub mod properties { pub use std :: collections :: HashSet ; pub use stageleft :: * ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , SeenTees } ; pub use crate :: properties :: PropertyDatabase ; # [doc = " Allows us to convert the hydroflow datatype for folds to a binary operation for the algebra"] # [doc = " property tests."] # [allow (dead_code)] pub fn convert_hf_to_binary < I , A : Default , F : Fn (& mut A , I) > (f : F) -> impl Fn (I , I) -> A { move | a , b | { let mut acc = Default :: default () ; f (& mut acc , a) ; f (& mut acc , b) ; acc } } # [cfg (stageleft_macro)] impl PropertyDatabase { # [doc = " Tags the expression as commutative."] pub fn add_commutative_tag < 'a , I , A , F : Fn (& mut A , I) , Q : Quoted < 'a , F > + Clone > (& mut self , expr : Q ,) -> Q { let expr_clone = expr . clone () ; self . commutative . insert (expr_clone . splice ()) ; expr } pub fn is_tagged_commutative (& self , expr : & syn :: Expr) -> bool { self . commutative . contains (expr) } } pub fn properties_optimize_node < 'a > (node : & mut HfPlusNode < 'a > , db : & PropertyDatabase , seen_tees : & mut SeenTees < 'a > ,) { node . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , seen_tees ,) ; match node { HfPlusNode :: ReduceKeyed { f , .. } if db . is_tagged_commutative (& f . 0) => { dbg ! ("IDENTIFIED COMMUTATIVE OPTIMIZATION for {:?}" , & f) ; } _ => { } } } pub fn properties_optimize < 'a > (ir : Vec < HfPlusLeaf < 'a > > , db : & PropertyDatabase ,) -> Vec < HfPlusLeaf < 'a > > { let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use super :: * ; use crate :: deploy :: SingleProcessGraph ; use crate :: FlowBuilder ; # [test] fn test_property_database () { let mut db = PropertyDatabase :: default () ; assert ! (! db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; let _ = db . add_commutative_tag (q ! (| a : & mut i32 , b : i32 | * a += b)) ; assert ! (db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; } # [test] fn test_property_optimized () { let flow = FlowBuilder :: new () ; let mut database = PropertyDatabase :: default () ; let process = flow . process :: < () > () ; let counter_func = q ! (| count : & mut i32 , _ | * count += 1) ; let _ = database . add_commutative_tag (counter_func) ; flow . source_iter (& process , q ! (vec ! [])) . map (q ! (| string : String | (string , ()))) . tick_batch () . fold_keyed (q ! (|| 0) , counter_func) . all_ticks () . for_each (q ! (| (string , count) | println ! ("{}: {}" , string , count))) ; let built = flow . finalize () . optimize_with (| ir | properties_optimize (ir , & database)) . with_default_optimize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let _ = built . compile_no_network :: < SingleProcessGraph > () ; } } } pub use crate :: RuntimeContext ; # [cfg (stageleft_macro)] impl Copy for RuntimeContext < '_ > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Context > for RuntimeContext < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (quote ! (& context))) } } pub use crate :: HfCompiled ; # [cfg (stageleft_macro)] impl < 'a , ID > HfCompiled < 'a , ID > { pub fn hydroflow_ir (& self) -> & BTreeMap < usize , HydroflowGraph > { & self . hydroflow_ir } } # [cfg (stageleft_macro)] impl < 'a > HfCompiled < 'a , usize > { pub fn with_dynamic_id (self , id : impl Quoted < 'a , usize >) -> HfBuiltWithId < 'a > { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; let mut conditioned_tokens = None ; for (subgraph_id , flat_graph) in self . hydroflow_ir { let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; let my_extra_stmts = self . extra_stmts . get (& subgraph_id) . cloned () . unwrap_or_default () ; if let Some (conditioned_tokens) = conditioned_tokens . as_mut () { * conditioned_tokens = syn :: parse_quote ! { # conditioned_tokens else if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } } ; } else { conditioned_tokens = Some (syn :: parse_quote ! { if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } }) ; } } let conditioned_tokens : TokenStream = conditioned_tokens . unwrap () ; let id = id . splice () ; HfBuiltWithId { tokens : syn :: parse_quote ! ({ let __given_id = # id ; # conditioned_tokens else { panic ! ("Invalid node id: {}" , __given_id) ; } }) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfCompiled < 'a , () > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfCompiled < 'a , () > { fn to_tokens (mut self) -> (Option < TokenStream > , Option < TokenStream >) { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; if self . hydroflow_ir . len () != 1 { panic ! ("Expected exactly one subgraph in the Hydroflow IR") ; } let flat_graph = self . hydroflow_ir . remove (& 0) . unwrap () ; let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; (None , Some (tokens)) } } pub use crate :: HfBuiltWithId ; # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfBuiltWithId < 'a > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfBuiltWithId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (self . tokens)) } }
[INFO] [stdout]   |
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] error: `box` patterns have been removed (feature `box_patterns`)
[INFO] [stdout]  --> /opt/rustwide/target/debug/build/hydroflow_plus/5672655b657d1e44/out/lib_pub.rs:1:91878
[INFO] [stdout]   |
[INFO] [stdout] 1 | ...> { if let HfPlusNode :: Unpersist (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: ...
[INFO] [stdout]   |                                                                   ^^^
[INFO] [stdout]   |
[INFO] [stdout]   = help: enable feature `deref_patterns` instead and...
[INFO] [stdout] help: ...if possible just remove keyword `box`...
[INFO] [stdout]   |
[INFO] [stdout] 1 - pub use std :: collections :: BTreeMap ; pub use std :: marker :: PhantomData ; pub use hydroflow :: scheduled :: context :: Context ; pub use hydroflow :: scheduled :: graph :: Hydroflow ; pub use hydroflow :: * ; pub use lang :: graph :: { partition_graph , HydroflowGraph } ; pub use proc_macro2 :: TokenStream ; pub use quote :: quote ; pub use stageleft :: runtime_support :: FreeVariable ; pub use stageleft :: Quoted ; pub mod runtime_support { pub use bincode ; } pub mod stream { pub use std :: cell :: RefCell ; pub use std :: hash :: Hash ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow :: bytes :: Bytes ; pub use hydroflow :: futures :: Sink ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: quote ; pub use serde :: de :: DeserializeOwned ; pub use serde :: Serialize ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use syn :: parse_quote ; pub use crate :: builder :: { ClusterIds , FlowLeaves } ; pub use crate :: cycle :: { CycleCollection , CycleComplete } ; pub use crate :: ir :: { DebugInstantiate , HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { CanSend , Location , LocationId } ; pub use crate :: { Cluster , Optional , Singleton } ; pub use crate :: stream :: Unbounded ; pub use crate :: stream :: Bounded ; pub use crate :: stream :: NoTick ; pub use crate :: stream :: Tick ; pub use crate :: stream :: Stream ; # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Stream { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Stream < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Stream { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , C , N > > ,) -> Stream < 'a , (T , O) , W , C , N > where O : Clone , { let other : Optional < 'a , O , Bounded , C , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn cross_product < O > (self , other : Stream < 'a , O , W , C , N >) -> Stream < 'a , (T , O) , W , C , N > where T : Clone , O : Clone , { if self . location_kind != other . location_kind { panic ! ("cross_product must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossProduct (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn union (self , other : Stream < 'a , T , W , C , N >) -> Stream < 'a , T , W , C , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn dest_sink < S : Unpin + Sink < T > + 'a > (self , sink : impl Quoted < 'a , S >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: DestSink { sink : sink . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn first (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } # [doc = " Allow this stream through if the other stream has elements, otherwise the output is empty."] pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } # [doc = " Allow this stream through if the other stream is empty, otherwise the output is empty."] pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn enumerate (self) -> Stream < 'a , (usize , T) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Enumerate (Box :: new (self . ir_node . into_inner ())) ,) } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn sort (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Ord , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Sort (Box :: new (self . ir_node . into_inner ())) ,) } pub fn count (self) -> Singleton < 'a , usize , Bounded , Tick , N > { self . fold (q ! (|| 0usize) , q ! (| count , _ | * count += 1)) } pub fn delta (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } pub fn unique (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Eq + Hash , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unique (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn tick_batch (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_prefix (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { self . tick_batch () . persist () } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn for_each < F : Fn (T) + 'a > (self , f : impl IntoQuotedMut < 'a , F >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: ForEach { input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , f : f . splice () . into () , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Unbounded , NoTick , N > { pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . tick_batch () . continue_if (samples . first ()) . all_ticks () } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Unbounded , NoTick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , C , N : Location > Stream < 'a , T , Bounded , C , N > { pub fn filter_not_in (self , other : Stream < 'a , T , Bounded , C , N >) -> Stream < 'a , T , Bounded , C , N > where T : Eq + Hash , { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Difference (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Stream < 'a , & T , W , C , N > { pub fn cloned (self) -> Stream < 'a , T , W , C , N > { self . map (q ! (| d | d . clone ())) } } # [cfg (stageleft_macro)] impl < 'a , K , V1 , W , C , N : Location > Stream < 'a , (K , V1) , W , C , N > { pub fn join < W2 , V2 > (self , n : Stream < 'a , (K , V2) , W2 , C , N > ,) -> Stream < 'a , (K , (V1 , V2)) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Join (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } pub fn anti_join < W2 > (self , n : Stream < 'a , K , W2 , C , N >) -> Stream < 'a , (K , V1) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("anti_join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: AntiJoin (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , K : Eq + Hash , V , N : Location > Stream < 'a , (K , V) , Bounded , Tick , N > { pub fn fold_keyed < A , I : Fn () -> A + 'a , F : Fn (& mut A , V) + 'a > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , A) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FoldKeyed { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce_keyed < F : Fn (& mut V , V) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , V) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: ReduceKeyed { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } pub fn get_this_crate () -> TokenStream { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , Span :: call_site ()) ; quote ! { # ident } } } } pub fn serialize_bincode < T : Serialize > (is_demux : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if is_demux { parse_quote ! { map (| (id , data) | { (id , # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into ()) }) } } else { parse_quote ! { map (| data | { # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into () }) } } } pub fn deserialize_bincode < T : DeserializeOwned > (tagged : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if tagged { parse_quote ! { map (| res | { let (id , b) = res . unwrap () ; (id , # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& b) . unwrap ()) }) } } else { parse_quote ! { map (| res | { # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& res . unwrap ()) . unwrap () }) } } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn send_bincode < N2 : Location , CoreType > (self , other : & N2 ,) -> Stream < 'a , N :: Out < CoreType > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T > , CoreType : Serialize + DeserializeOwned , { let serialize_pipeline = Some (serialize_bincode :: < CoreType > (N :: is_demux ())) ; let deserialize_pipeline = Some (deserialize_bincode :: < CoreType > (N :: is_tagged ())) ; Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bytes < N2 : Location > (self , other : & N2 ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T > , { Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline : None , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline : if N :: is_tagged () { Some (parse_quote ! (map (| (id , b) | (id , b . unwrap () . freeze ())))) } else { Some (parse_quote ! (map (| b | b . unwrap () . freeze ()))) } , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bincode_interleaved < N2 : Location , Tag , CoreType > (self , other : & N2 ,) -> Stream < 'a , CoreType , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T , Out < CoreType > = (Tag , CoreType) > , CoreType : Serialize + DeserializeOwned , { self . send_bincode :: < N2 , CoreType > (other) . map (q ! (| (_ , b) | b)) } pub fn send_bytes_interleaved < N2 : Location , Tag > (self , other : & N2 ,) -> Stream < 'a , Bytes , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T , Out < Bytes > = (Tag , Bytes) > , { self . send_bytes :: < N2 > (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bincode < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < T > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) > , T : Clone + Serialize + DeserializeOwned , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bincode (other) } pub fn broadcast_bincode_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , T , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) , Out < T > = (Tag , T) > + 'a , T : Clone + Serialize + DeserializeOwned , { self . broadcast_bincode (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bytes < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) > + 'a , T : Clone , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bytes (other) } pub fn broadcast_bytes_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , Bytes , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) , Out < Bytes > = (Tag , Bytes) > + 'a , T : Clone , { self . broadcast_bytes (other) . map (q ! (| (_ , b) | b)) } } } pub use stream :: { Bounded , NoTick , Stream , Tick , Unbounded } ; pub mod singleton { pub use std :: cell :: RefCell ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use crate :: builder :: FlowLeaves ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial , CycleComplete } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: Stream ; pub use crate :: singleton :: CrossResult ; # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Singleton < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Singleton :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } pub use crate :: singleton :: Singleton ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Singleton { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleComplete < 'a > for Singleton < 'a , T , Bounded , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleCollectionWithInitial < 'a > for Singleton < 'a , T , Bounded , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , initial : Self , l : LocationId ,) -> Self { Singleton :: new (l , ir_leaves , HfPlusNode :: Union (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , }) , initial . ir_node . into_inner () . into () ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Singleton < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Singleton { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , U , W , C , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (Self :: other_ir_node (other)) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Singleton < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CrossSingleton (Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , Box :: new (HfPlusNode :: Unpersist (Box :: new (Self :: other_ir_node (other)))) ,))) ,) } } pub use crate :: singleton :: Optional ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Optional { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } pub fn some (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: new (singleton . location_kind , singleton . ir_leaves , singleton . ir_node . into_inner () ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > From < Singleton < 'a , T , W , C , N > > for Optional < 'a , T , W , C , N > { fn from (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: some (singleton) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Optional < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Optional { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn into_stream (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , Tick , N > > ,) -> Optional < 'a , (T , O) , Bounded , Tick , N > where O : Clone , { let other : Optional < 'a , O , Bounded , Tick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn union (self , other : Optional < 'a , T , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Optional < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_samples (self) -> Stream < 'a , T , Unbounded , NoTick , N > { self . latest_tick () . all_ticks () } pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . latest_tick () . continue_if (samples . first ()) . latest () . tick_samples () } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Unbounded , NoTick , N > > ,) -> Optional < 'a , (T , O) , Unbounded , NoTick , N > where O : Clone , { let other : Optional < 'a , O , Unbounded , NoTick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } self . latest_tick () . cross_singleton (other . latest_tick ()) . latest () } } } pub use singleton :: { Optional , Singleton } ; pub mod location { pub use std :: marker :: PhantomData ; pub use crate :: location :: LocationId ; pub use crate :: location :: Location ; pub use crate :: location :: Process ; # [cfg (stageleft_macro)] impl < P > Clone for Process < P > { fn clone (& self) -> Self { Process { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < P > Location for Process < P > { fn id (& self) -> LocationId { LocationId :: Process (self . id) } } pub use crate :: location :: Cluster ; # [cfg (stageleft_macro)] impl < C > Clone for Cluster < C > { fn clone (& self) -> Self { Cluster { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < C > Location for Cluster < C > { fn id (& self) -> LocationId { LocationId :: Cluster (self . id) } } pub use crate :: location :: CanSend ; # [cfg (stageleft_macro)] impl < P1 , P2 > CanSend < Process < P2 > > for Process < P1 > { type In < T > = T ; type Out < T > = T ; fn is_demux () -> bool { false } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < P1 , C2 > CanSend < Cluster < C2 > > for Process < P1 > { type In < T > = (u32 , T) ; type Out < T > = T ; fn is_demux () -> bool { true } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < C1 , P2 > CanSend < Process < P2 > > for Cluster < C1 > { type In < T > = T ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { false } fn is_tagged () -> bool { true } } # [cfg (stageleft_macro)] impl < C1 , C2 > CanSend < Cluster < C2 > > for Cluster < C1 > { type In < T > = (u32 , T) ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { true } fn is_tagged () -> bool { true } } } pub use location :: { Cluster , Process } ; pub mod deploy { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use stageleft :: Quoted ; pub mod graphs { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use super :: { LocalDeploy , Node , ProcessSpec } ; pub use crate :: deploy :: graphs :: SingleProcessGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for SingleProcessGraph { type Process = SingleNode ; type Cluster = SingleNode ; type Meta = () ; type GraphId = () ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { SingleNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { SingleNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , SingleProcessGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> SingleNode { SingleNode { } } } pub use crate :: deploy :: graphs :: SingleNode ; # [cfg (stageleft_macro)] impl Node for SingleNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } pub use crate :: deploy :: graphs :: MultiGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for MultiGraph { type Process = MultiNode ; type Cluster = MultiNode ; type Meta = () ; type GraphId = usize ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { MultiNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { MultiNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , MultiGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> MultiNode { MultiNode { } } } pub use crate :: deploy :: graphs :: MultiNode ; # [cfg (stageleft_macro)] impl Node for MultiNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } } pub use graphs :: * ; pub use crate :: deploy :: LocalDeploy ; pub use crate :: deploy :: Deploy ; # [cfg (stageleft_macro)] impl < 'a , T : Deploy < 'a , Process = N , Cluster = C , Meta = M , GraphId = R > , N : Node < Meta = M > , C : Node < Meta = M > , M : Default , R , > LocalDeploy < 'a > for T { type Process = N ; type Cluster = C ; type Meta = M ; type GraphId = R ; fn has_trivial_node () -> bool { < T as Deploy < 'a > > :: has_trivial_node () } fn trivial_process (id : usize) -> Self :: Process { < T as Deploy < 'a > > :: trivial_process (id) } fn trivial_cluster (id : usize) -> Self :: Cluster { < T as Deploy < 'a > > :: trivail_cluster (id) } } pub use crate :: deploy :: ProcessSpec ; pub use crate :: deploy :: ClusterSpec ; pub use crate :: deploy :: Node ; } pub use deploy :: { ClusterSpec , Deploy , ProcessSpec } ; pub mod cycle { pub use std :: marker :: PhantomData ; pub use crate :: builder :: FlowLeaves ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: cycle :: CycleComplete ; pub use crate :: cycle :: CycleCollection ; pub use crate :: cycle :: CycleCollectionWithInitial ; pub use crate :: cycle :: HfCycle ; # [cfg (stageleft_macro)] impl < 'a , S : CycleComplete < 'a > > HfCycle < 'a , S > { pub fn complete (self , stream : S) { let ident = self . ident ; S :: complete (stream , ident) } } } pub use cycle :: HfCycle ; pub mod builder { pub use std :: cell :: RefCell ; pub use std :: collections :: HashMap ; pub use std :: marker :: PhantomData ; pub use std :: rc :: Rc ; pub use std :: time :: Duration ; pub use hydroflow :: futures :: stream :: Stream as FuturesStream ; pub use hydroflow :: { tokio , tokio_stream } ; pub use internal :: TokenStream ; pub use proc_macro2 :: Span ; pub use quote :: quote ; pub use runtime_support :: FreeVariable ; pub use stageleft :: * ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Cluster , Location , LocationId , Process } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: { HfCycle , Optional , RuntimeContext , Singleton , Stream } ; pub mod built { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use hydroflow_lang :: graph :: { eliminate_extra_unions_tees , HydroflowGraph } ; pub use super :: deploy :: { DeployFlow , DeployResult } ; pub use crate :: deploy :: { ClusterSpec , Deploy , LocalDeploy , ProcessSpec } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Cluster , Process } ; pub use crate :: HfCompiled ; pub use crate :: builder :: built :: BuiltFlow ; # [cfg (stageleft_macro)] impl < 'a > Drop for BuiltFlow < 'a > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped BuiltFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn ir (& self) -> & Vec < HfPlusLeaf < 'a > > { & self . ir } pub fn optimize_with (mut self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> BuiltFlow < 'a > { self . used = true ; BuiltFlow { ir : f (std :: mem :: take (& mut self . ir)) , processes : std :: mem :: take (& mut self . processes) , clusters : std :: mem :: take (& mut self . clusters) , used : false , _phantom : PhantomData , } } } pub fn build_inner (ir : & mut Vec < HfPlusLeaf >) -> BTreeMap < usize , HydroflowGraph > { let mut builders = BTreeMap :: new () ; let mut built_tees = HashMap :: new () ; let mut next_stmt_id = 0 ; for leaf in ir { leaf . emit (& mut builders , & mut built_tees , & mut next_stmt_id) ; } builders . into_iter () . map (| (k , v) | { let (mut flat_graph , _ , _) = v . build () ; eliminate_extra_unions_tees (& mut flat_graph) ; (k , flat_graph) }) . collect () } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn compile_no_network < D : LocalDeploy < 'a > > (mut self) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; HfCompiled { hydroflow_ir : build_inner (& mut self . ir) , extra_stmts : BTreeMap :: new () , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> BuiltFlow < 'a > { self . optimize_with (crate :: persist_pullup :: persist_pullup) } fn into_deploy < D : LocalDeploy < 'a > > (mut self) -> DeployFlow < 'a , D > { self . used = true ; let processes = if D :: has_trivial_node () { self . processes . iter () . map (| id | (* id , D :: trivial_process (* id))) . collect () } else { HashMap :: new () } ; let clusters = if D :: has_trivial_node () { self . clusters . iter () . map (| id | (* id , D :: trivial_cluster (* id))) . collect () } else { HashMap :: new () } ; DeployFlow { ir : std :: mem :: take (& mut self . ir) , nodes : processes , clusters , used : false , _phantom : PhantomData , } } pub fn with_process < P , D : LocalDeploy < 'a > > (self , process : & Process < P > , spec : impl ProcessSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_process (process , spec) } pub fn with_cluster < C , D : LocalDeploy < 'a > > (self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_cluster (cluster , spec) } pub fn compile < D : Deploy < 'a > + 'a > (self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . into_deploy :: < D > () . compile (env) } pub fn deploy < D : Deploy < 'a , CompileEnv = () > + 'a > (self , env : & mut D :: InstantiateEnv ,) -> DeployResult < 'a , D > { self . into_deploy :: < D > () . deploy (env) } } } pub mod deploy { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use proc_macro2 :: Span ; pub use stageleft :: Quoted ; pub use super :: built :: build_inner ; pub use crate :: deploy :: { LocalDeploy , Node } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: { Cluster , ClusterSpec , Deploy , HfCompiled , Process , ProcessSpec } ; pub use crate :: builder :: deploy :: DeployFlow ; # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > Drop for DeployFlow < 'a , D > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped DeployFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > DeployFlow < 'a , D > { pub fn with_process < P > (mut self , process : & Process < P > , spec : impl ProcessSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < P > () . to_string () ; self . nodes . insert (process . id , spec . build (process . id , & tag_name)) ; self } pub fn with_cluster < C > (mut self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < C > () . to_string () ; self . clusters . insert (cluster . id , spec . build (cluster . id , & tag_name)) ; self } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployFlow < 'a , D > { pub fn compile (mut self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; let mut seen_tees : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | leaf . compile_network :: < D > (env , & mut seen_tees , & self . nodes , & self . clusters)) . collect () ; let extra_stmts = self . extra_stmts (env) ; HfCompiled { hydroflow_ir : build_inner (& mut ir_leaves_networked) , extra_stmts , _phantom : PhantomData , } } fn extra_stmts (& self , env : & < D as Deploy < 'a > > :: CompileEnv) -> BTreeMap < usize , Vec < syn :: Stmt > > { let all_locations_count = self . nodes . len () + self . clusters . len () ; let mut extra_stmts : BTreeMap < usize , Vec < syn :: Stmt > > = BTreeMap :: new () ; for & c_id in self . clusters . keys () { let self_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , c_id) , Span :: call_site () ,) ; let self_id_expr = D :: cluster_self_id (env) . splice () ; extra_stmts . entry (c_id) . or_default () . push (syn :: parse_quote ! { let # self_id_ident = # self_id_expr ; }) ; for other_location in 0 .. all_locations_count { let other_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , c_id) , Span :: call_site () ,) ; let other_id_expr = D :: cluster_ids (env , c_id) . splice () ; extra_stmts . entry (other_location) . or_default () . push (syn :: parse_quote ! { let # other_id_ident = # other_id_expr ; }) ; } } extra_stmts } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a , CompileEnv = () > > DeployFlow < 'a , D > { # [must_use] pub fn deploy (mut self , env : & mut D :: InstantiateEnv) -> DeployResult < 'a , D > { self . used = true ; let mut seen_tees_instantiate : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | { leaf . compile_network :: < D > (& () , & mut seen_tees_instantiate , & self . nodes , & self . clusters ,) }) . collect () ; let mut compiled = build_inner (& mut ir_leaves_networked) ; let mut extra_stmts = self . extra_stmts (& ()) ; let mut meta = D :: Meta :: default () ; let (mut processes , mut clusters) = (std :: mem :: take (& mut self . nodes) . into_iter () . map (| (node_id , node) | { node . instantiate (env , & mut meta , compiled . remove (& node_id) . unwrap () , extra_stmts . remove (& node_id) . unwrap_or_default () ,) ; (node_id , node) }) . collect :: < HashMap < _ , _ > > () , std :: mem :: take (& mut self . clusters) . into_iter () . map (| (cluster_id , cluster) | { cluster . instantiate (env , & mut meta , compiled . remove (& cluster_id) . unwrap () , extra_stmts . remove (& cluster_id) . unwrap_or_default () ,) ; (cluster_id , cluster) }) . collect :: < HashMap < _ , _ > > () ,) ; for node in processes . values_mut () { node . update_meta (& meta) ; } for cluster in clusters . values_mut () { cluster . update_meta (& meta) ; } let mut seen_tees_connect = HashMap :: new () ; for leaf in ir_leaves_networked { leaf . connect_network (& mut seen_tees_connect) ; } DeployResult { processes , clusters , } } } pub use crate :: builder :: deploy :: DeployResult ; # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployResult < 'a , D > { pub fn get_process < P > (& self , p : & Process < P >) -> & D :: Process { let id = match p . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . processes . get (& id) . unwrap () } pub fn get_cluster < C > (& self , c : & Cluster < C >) -> & D :: Cluster { let id = match c . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . clusters . get (& id) . unwrap () } } } # [doc = " Tracks the leaves of the dataflow IR. This is referenced by"] # [doc = " `Stream` and `HfCycle` to build the IR. The inner option will"] # [doc = " be set to `None` when this builder is finalized."] pub type FlowLeaves < 'a > = Rc < RefCell < Option < Vec < HfPlusLeaf < 'a > > > > > ; pub use crate :: builder :: ClusterIds ; # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Vec < u32 > > for ClusterIds < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , & 'a Vec < u32 > > for ClusterIds < 'a > { } # [derive (Copy , Clone)] pub struct ClusterSelfId < 'a > { pub id : usize , pub _phantom : PhantomData < & 'a mut & 'a u32 > , } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < u32 > for ClusterSelfId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , u32 > for ClusterSelfId < 'a > { } pub use crate :: builder :: FlowBuilder ; # [cfg (stageleft_macro)] impl < 'a > Drop for FlowBuilder < 'a > { fn drop (& mut self) { if ! self . finalized { panic ! ("Dropped FlowBuilder without finalizing, you may have forgotten to call `with_default_optimize`, `optimize_with`, or `finalize`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > QuotedContext for FlowBuilder < 'a > { fn create () -> Self { FlowBuilder :: new () } } # [cfg (stageleft_macro)] impl < 'a > FlowBuilder < 'a > { # [allow (clippy :: new_without_default)] pub fn new () -> FlowBuilder < 'a > { FlowBuilder { ir_leaves : Rc :: new (RefCell :: new (Some (Vec :: new ()))) , nodes : RefCell :: new (vec ! []) , clusters : RefCell :: new (vec ! []) , cycle_ids : RefCell :: new (HashMap :: new ()) , next_node_id : RefCell :: new (0) , finalized : false , _phantom : PhantomData , } } pub fn finalize (mut self) -> built :: BuiltFlow < 'a > { self . finalized = true ; built :: BuiltFlow { ir : self . ir_leaves . borrow_mut () . take () . unwrap () , processes : self . nodes . replace (vec ! []) , clusters : self . clusters . replace (vec ! []) , used : false , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> built :: BuiltFlow < 'a > { self . finalize () . with_default_optimize () } pub fn optimize_with (self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> built :: BuiltFlow < 'a > { self . finalize () . optimize_with (f) } pub fn ir_leaves (& self) -> & FlowLeaves < 'a > { & self . ir_leaves } pub fn process < P > (& self) -> Process < P > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . nodes . borrow_mut () . push (id) ; Process { id , _phantom : PhantomData , } } pub fn cluster < C > (& self) -> Cluster < C > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . clusters . borrow_mut () . push (id) ; Cluster { id , _phantom : PhantomData , } } pub fn runtime_context (& self) -> RuntimeContext < 'a > { RuntimeContext { _phantom : PhantomData , } } pub fn cluster_members < C > (& self , cluster : & Cluster < C > ,) -> impl Quoted < 'a , & 'a Vec < u32 > > + Copy + 'a { ClusterIds { id : cluster . id , _phantom : PhantomData , } } pub fn cluster_self_id < C > (& self , cluster : & Cluster < C >) -> impl Quoted < 'a , u32 > + Copy + 'a { ClusterSelfId { id : cluster . id , _phantom : PhantomData , } } pub fn spin < L : Location > (& self , on : & L) -> Stream < 'a , () , Unbounded , NoTick , L > { Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Spin () , location_kind : on . id () , })) ,) } pub fn spin_batch < L : Location > (& self , on : & L , batch_size : impl Quoted < 'a , usize > + Copy + 'a ,) -> Stream < 'a , () , Bounded , Tick , L > { self . spin (on) . flat_map (q ! (move | _ | 0 .. batch_size)) . map (q ! (| _ | ())) . tick_batch () } pub fn source_stream < T , E : FuturesStream < Item = T > + Unpin , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Unbounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Stream (e . into ()) , location_kind : on . id () , })) ,) } pub fn source_iter < T , E : IntoIterator < Item = T > , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Bounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , })) ,) } pub fn singleton < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Singleton < 'a , T , Bounded , NoTick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Singleton :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,)))) ,) } pub fn singleton_first_tick < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Optional < 'a , T , Bounded , Tick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,) } pub fn source_interval < L : Location > (& self , on : & L , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , () , Unbounded , NoTick , L > { let interval = interval . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : on . id () , })) ,) } pub fn source_interval_delayed < L : Location > (& self , on : & L , delay : impl Quoted < 'a , Duration > + Copy + 'a , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , tokio :: time :: Instant , Unbounded , NoTick , L > { self . source_stream (on , q ! (tokio_stream :: wrappers :: IntervalStream :: new (tokio :: time :: interval_at (tokio :: time :: Instant :: now () + delay , interval))) ,) . tick_batch () . first () . latest () } pub fn cycle < S : CycleCollection < 'a > > (& self , on : & S :: Location) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , on . id ()) ,) } pub fn cycle_with_initial < S : CycleCollectionWithInitial < 'a > > (& self , on : & S :: Location , initial : S ,) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , initial , on . id ()) ,) } } } pub use builder :: FlowBuilder ; pub mod ir { pub use core :: panic ; pub use std :: cell :: RefCell ; pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow_lang :: graph :: FlatGraphBuilder ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: ToTokens ; pub use syn :: parse_quote ; pub use crate :: deploy :: Deploy ; pub use crate :: location :: LocationId ; pub use crate :: ir :: DebugExpr ; # [cfg (stageleft_macro)] impl From < syn :: Expr > for DebugExpr { fn from (expr : syn :: Expr) -> DebugExpr { DebugExpr (expr) } } # [cfg (stageleft_macro)] impl Deref for DebugExpr { type Target = syn :: Expr ; fn deref (& self) -> & Self :: Target { & self . 0 } } # [cfg (stageleft_macro)] impl ToTokens for DebugExpr { fn to_tokens (& self , tokens : & mut TokenStream) { self . 0 . to_tokens (tokens) ; } } # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugExpr { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "{}" , self . 0 . to_token_stream ()) } } pub use crate :: ir :: DebugInstantiate ; # [cfg (stageleft_macro)] impl < 'a > std :: fmt :: Debug for DebugInstantiate < 'a > { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<network instantiate>") } } pub use crate :: ir :: DebugPipelineFn ; # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugPipelineFn { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<function>") } } pub use crate :: ir :: HfPlusSource ; pub use crate :: ir :: HfPlusLeaf ; # [cfg (stageleft_macro)] impl < 'a > HfPlusLeaf < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . compile_network :: < D > (compile_env , s , nodes , clusters) ; } , seen_tees ,) } pub fn connect_network (self , seen_tees : & mut SeenTees < 'a >) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . connect_network (s) ; } , seen_tees ,) } pub fn transform_children (self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) -> HfPlusLeaf < 'a > { match self { HfPlusLeaf :: ForEach { f , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: ForEach { f , input } } HfPlusLeaf :: DestSink { sink , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: DestSink { sink , input } } HfPlusLeaf :: CycleSink { ident , location_kind , mut input , } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: CycleSink { ident , location_kind , input , } } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) { match self { HfPlusLeaf :: ForEach { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> for_each (# f) ; }) ; } HfPlusLeaf :: DestSink { sink , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink) ; }) ; } HfPlusLeaf :: CycleSink { ident , location_kind , input , } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; assert_eq ! (input_location_id , * location_id , "cycle_sink location mismatch") ; graph_builders . entry (* location_id) . or_default () . add_statement (parse_quote ! { # ident = # input_ident ; }) ; } } } } pub use crate :: ir :: HfPlusNode ; pub type SeenTees < 'a > = HashMap < * const RefCell < HfPlusNode < 'a > > , Rc < RefCell < HfPlusNode < 'a > > > > ; # [cfg (stageleft_macro)] impl < 'a > HfPlusNode < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (& mut self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) { self . transform_children (| n , s | n . compile_network :: < D > (compile_env , s , nodes , clusters) , seen_tees ,) ; if let HfPlusNode :: Network { from_location , to_location , instantiate_fn , .. } = self { let (sink_expr , source_expr , connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { let ((sink , source) , connect_fn) = match (from_location , to_location) { (LocationId :: Process (from) , LocationId :: Process (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: o2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Process (from) , LocationId :: Cluster (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: o2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Process (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: m2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Cluster (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: m2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } } ; (sink , source , connect_fn) } DebugInstantiate :: Finalized (_ , _ , _) => panic ! ("network already finalized") , } ; * instantiate_fn = DebugInstantiate :: Finalized (sink_expr , source_expr , connect_fn) ; } } pub fn connect_network (& mut self , seen_tees : & mut SeenTees < 'a >) { self . transform_children (| n , s | n . connect_network (s) , seen_tees) ; if let HfPlusNode :: Network { instantiate_fn , .. } = self { match instantiate_fn { DebugInstantiate :: Building () => panic ! ("network not built") , DebugInstantiate :: Finalized (_ , _ , ref connect_fn) => { connect_fn () ; } } } } pub fn transform_children (& mut self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) { match self { HfPlusNode :: Placeholder => { panic ! () ; } HfPlusNode :: Source { .. } => { } HfPlusNode :: CycleSource { .. } => { } HfPlusNode :: Tee { inner } => { if let Some (transformed) = seen_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { * inner = transformed . clone () ; } else { let transformed_cell = Rc :: new (RefCell :: new (HfPlusNode :: Placeholder)) ; seen_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , transformed_cell . clone () ,) ; let mut orig = inner . replace (HfPlusNode :: Placeholder) ; transform (& mut orig , seen_tees) ; * transformed_cell . borrow_mut () = orig ; * inner = transformed_cell ; } } HfPlusNode :: Persist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Unpersist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Delta (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Union (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossProduct (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossSingleton (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Join (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Difference (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: AntiJoin (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Map { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FlatMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Filter { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FilterMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Sort (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: DeferTick (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Enumerate (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Inspect { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Unique (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Fold { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FoldKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Reduce { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: ReduceKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Network { input , .. } => { transform (input . as_mut () , seen_tees) ; } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) -> (syn :: Ident , usize) { match self { HfPlusNode :: Placeholder => { panic ! () } HfPlusNode :: Persist (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let persist_id = * next_stmt_id ; * next_stmt_id += 1 ; let persist_ident = syn :: Ident :: new (& format ! ("stream_{}" , persist_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # persist_ident = # inner_ident -> persist ::<'static > () ; }) ; (persist_ident , location) } HfPlusNode :: Unpersist (_) => { panic ! ("Unpersist is a marker node and should have been optimized away. This is likely a compiler bug.") } HfPlusNode :: Delta (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let delta_id = * next_stmt_id ; * next_stmt_id += 1 ; let delta_ident = syn :: Ident :: new (& format ! ("stream_{}" , delta_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # delta_ident = # inner_ident -> multiset_delta () ; }) ; (delta_ident , location) } HfPlusNode :: Source { source , location_kind , } => { let source_id = * next_stmt_id ; * next_stmt_id += 1 ; let source_ident = syn :: Ident :: new (& format ! ("stream_{}" , source_id) , Span :: call_site ()) ; let source_stmt = match source { HfPlusSource :: Stream (expr) => { parse_quote ! { # source_ident = source_stream (# expr) ; } } HfPlusSource :: Iter (expr) => { parse_quote ! { # source_ident = source_iter (# expr) ; } } HfPlusSource :: Interval (expr) => { parse_quote ! { # source_ident = source_interval (# expr) ; } } HfPlusSource :: Spin () => { parse_quote ! { # source_ident = spin () ; } } } ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; graph_builders . entry (* location_id) . or_default () . add_statement (source_stmt) ; (source_ident , * location_id) } HfPlusNode :: CycleSource { ident , location_kind , } => { let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; (ident . clone () , * location_id) } HfPlusNode :: Tee { inner } => { if let Some (ret) = built_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { ret . clone () } else { let (inner_ident , inner_location_id) = inner . borrow () . emit (graph_builders , built_tees , next_stmt_id) ; let tee_id = * next_stmt_id ; * next_stmt_id += 1 ; let tee_ident = syn :: Ident :: new (& format ! ("stream_{}" , tee_id) , Span :: call_site ()) ; let builder = graph_builders . entry (inner_location_id) . or_default () ; builder . add_statement (parse_quote ! { # tee_ident = # inner_ident -> tee () ; }) ; built_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , (tee_ident . clone () , inner_location_id) ,) ; (tee_ident , inner_location_id) } } HfPlusNode :: Union (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "union inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let union_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # union_ident = union () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [0] # union_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # union_ident ; }) ; (union_ident , left_location_id) } HfPlusNode :: CrossSingleton (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "cross_singleton inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let cross_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # cross_ident = cross_singleton () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [input] # cross_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [single] # cross_ident ; }) ; (cross_ident , left_location_id) } HfPlusNode :: CrossProduct (..) | HfPlusNode :: Join (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: CrossProduct (..)) { parse_quote ! (cross_join_multiset) } else { parse_quote ! (join_multiset) } ; let (HfPlusNode :: CrossProduct (left , right) | HfPlusNode :: Join (left , right)) = self else { unreachable ! () } ; let (left_inner , left_was_persist) = if let HfPlusNode :: Persist (left) = left . as_ref () { (left , true) } else { (left , false) } ; let (right_inner , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left_inner . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right_inner . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "join / cross product inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; match (left_was_persist , right_was_persist) { (true , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'static > () ; }) ; } (true , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'tick > () ; }) ; } (false , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } (false , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } } ; builder . add_statement (parse_quote ! { # left_ident -> [0] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Difference (..) | HfPlusNode :: AntiJoin (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Difference (..)) { parse_quote ! (difference_multiset) } else { parse_quote ! (anti_join_multiset) } ; let (HfPlusNode :: Difference (left , right) | HfPlusNode :: AntiJoin (left , right)) = self else { unreachable ! () } ; let (right , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "difference / anti join inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; if right_was_persist { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } else { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } builder . add_statement (parse_quote ! { # left_ident -> [pos] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [neg] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Map { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let map_id = * next_stmt_id ; * next_stmt_id += 1 ; let map_ident = syn :: Ident :: new (& format ! ("stream_{}" , map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # map_ident = # input_ident -> map (# f) ; }) ; (map_ident , input_location_id) } HfPlusNode :: FlatMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let flat_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let flat_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , flat_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # flat_map_ident = # input_ident -> flat_map (# f) ; }) ; (flat_map_ident , input_location_id) } HfPlusNode :: Filter { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_ident = # input_ident -> filter (# f) ; }) ; (filter_ident , input_location_id) } HfPlusNode :: FilterMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_map_ident = # input_ident -> filter_map (# f) ; }) ; (filter_map_ident , input_location_id) } HfPlusNode :: Sort (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sort_id = * next_stmt_id ; * next_stmt_id += 1 ; let sort_ident = syn :: Ident :: new (& format ! ("stream_{}" , sort_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # sort_ident = # input_ident -> sort () ; }) ; (sort_ident , input_location_id) } HfPlusNode :: DeferTick (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let defer_tick_id = * next_stmt_id ; * next_stmt_id += 1 ; let defer_tick_ident = syn :: Ident :: new (& format ! ("stream_{}" , defer_tick_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # defer_tick_ident = # input_ident -> defer_tick_lazy () ; }) ; (defer_tick_ident , input_location_id) } HfPlusNode :: Enumerate (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let enumerate_id = * next_stmt_id ; * next_stmt_id += 1 ; let enumerate_ident = syn :: Ident :: new (& format ! ("stream_{}" , enumerate_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # enumerate_ident = # input_ident -> enumerate () ; }) ; (enumerate_ident , input_location_id) } HfPlusNode :: Inspect { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let inspect_id = * next_stmt_id ; * next_stmt_id += 1 ; let inspect_ident = syn :: Ident :: new (& format ! ("stream_{}" , inspect_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # inspect_ident = # input_ident -> inspect (# f) ; }) ; (inspect_ident , input_location_id) } HfPlusNode :: Unique (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let unique_id = * next_stmt_id ; * next_stmt_id += 1 ; let unique_ident = syn :: Ident :: new (& format ! ("stream_{}" , unique_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # unique_ident = # input_ident -> unique ::<'tick > () ; }) ; (unique_ident , input_location_id) } HfPlusNode :: Fold { .. } | HfPlusNode :: FoldKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Fold { .. }) { parse_quote ! (fold) } else { parse_quote ! (fold_keyed) } ; let (HfPlusNode :: Fold { init , acc , input } | HfPlusNode :: FoldKeyed { init , acc , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let fold_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'static > (# init , # acc) ; }) ; } else { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'tick > (# init , # acc) ; }) ; } (fold_ident , input_location_id) } HfPlusNode :: Reduce { .. } | HfPlusNode :: ReduceKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Reduce { .. }) { parse_quote ! (reduce) } else { parse_quote ! (reduce_keyed) } ; let (HfPlusNode :: Reduce { f , input } | HfPlusNode :: ReduceKeyed { f , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let reduce_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'static > (# f) ; }) ; } else { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'tick > (# f) ; }) ; } (reduce_ident , input_location_id) } HfPlusNode :: Network { from_location : _ , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input , } => { let (sink_expr , source_expr , _connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { panic ! ("Expected the network to be finalized") } DebugInstantiate :: Finalized (sink , source , connect_fn) => { (sink , source , connect_fn) } } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sender_builder = graph_builders . entry (input_location_id) . or_default () ; if let Some (serialize_pipeline) = serialize_pipeline { sender_builder . add_statement (parse_quote ! { # input_ident -> # serialize_pipeline -> dest_sink (# sink_expr) ; }) ; } else { sender_builder . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink_expr) ; }) ; } let to_id = match to_location { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let receiver_builder = graph_builders . entry (* to_id) . or_default () ; let receiver_stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let receiver_stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , receiver_stream_id) , Span :: call_site ()) ; if let Some (deserialize_pipeline) = deserialize_pipeline { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) -> # deserialize_pipeline ; }) ; } else { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) ; }) ; } (receiver_stream_ident , * to_id) } } } } } pub mod persist_pullup { pub use std :: cell :: RefCell ; pub use std :: collections :: HashSet ; pub use std :: ops :: Deref ; pub use crate :: ir :: * ; pub fn persist_pullup_node < 'a > (node : & mut HfPlusNode < 'a > , seen_tees : & mut SeenTees < 'a > , persist_pulled_tees : & mut HashSet < * const RefCell < HfPlusNode < 'a > > > ,) { node . transform_children (| n , s | persist_pullup_node (n , s , persist_pulled_tees) , seen_tees ,) ; match node { HfPlusNode :: Unpersist (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Unpersist (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Delta (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Delta (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Tee { inner } => { if persist_pulled_tees . contains (& (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >)) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } else { let inner_borrow = inner . borrow () ; if let HfPlusNode :: Persist (_) = inner_borrow . deref () { drop (inner_borrow) ; persist_pulled_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >) ; if let HfPlusNode :: Persist (box behind_persist) = inner . replace (HfPlusNode :: Placeholder) { * inner . borrow_mut () = behind_persist ; } else { unreachable ! () } * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } } } HfPlusNode :: Map { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Map { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Map { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: FlatMap { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: FlatMap { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: FlatMap { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Filter { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Filter { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Filter { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Network { input : box HfPlusNode :: Persist (_) , .. } => { if let HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Union (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Union (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Union (left , right))) ; } else { unreachable ! () } } HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: CrossProduct (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,) ,)))) ; } else { unreachable ! () } } HfPlusNode :: Join (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Join (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: Join (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,))))) ; } else { unreachable ! () } } _ => { } } } pub fn persist_pullup (ir : Vec < HfPlusLeaf >) -> Vec < HfPlusLeaf > { let mut seen_tees = Default :: default () ; let mut persist_pulled_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| n , s | persist_pullup_node (n , s , & mut persist_pulled_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn persist_pullup_through_map () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } # [test] fn persist_pullup_behind_tee () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; let before_tee = flow . source_iter (& process , q ! (0 .. 10)) . tick_batch () . persist () ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } } } pub mod profiler { pub use std :: cell :: RefCell ; pub use hydroflow :: futures :: channel :: mpsc :: UnboundedSender ; pub use stageleft :: * ; pub use crate as hydroflow_plus ; pub use crate :: ir :: * ; pub use crate :: RuntimeContext ; pub fn increment_counter (count : & mut u64) { * count += 1 ; } pub fn quoted_any_fn < 'a , F : Fn (& usize) + 'a , Q : IntoQuotedMut < 'a , F > > (q : Q) -> Q { q } # [doc = " Add a profiling node before each node to count the cardinality of its input"] pub fn add_profiling_node < 'a > (node : & mut HfPlusNode < 'a > , _context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > , id : & mut u32 , seen_tees : & mut SeenTees < 'a > ,) { let my_id = * id ; * id += 1 ; node . transform_children (| node , seen_tees | { add_profiling_node (node , _context , counters , counter_queue , id , seen_tees) } , seen_tees ,) ; let orig_node = std :: mem :: replace (node , HfPlusNode :: Placeholder) ; * node = HfPlusNode :: Inspect { f : quoted_any_fn (q ! ({ counter_queue . borrow () . unbounded_send ((my_id as usize , counters . borrow () [my_id as usize])) . unwrap () ; counters . borrow_mut () [my_id as usize] = 0 ; move | _ | { hydroflow_plus :: profiler :: increment_counter (& mut counters . borrow_mut () [my_id as usize] ,) ; } })) . splice () . into () , input : Box :: new (orig_node) , } } # [doc = " Count the cardinality of each input and periodically output to a file"] pub fn profiling < 'a > (ir : Vec < HfPlusLeaf < 'a > > , context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > ,) -> Vec < HfPlusLeaf < 'a > > { let mut id = 0 ; let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | { add_profiling_node (node , context , counters , counter_queue , & mut id , seen_tees) } , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn profiler_wrapping_all_operators () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let runtime_context = flow . runtime_context () ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (& built . ir ()) ; let counters = RuntimeData :: new ("Fake") ; let counter_queue = RuntimeData :: new ("Fake") ; let pushed_down = built . with_default_optimize () . optimize_with (| ir | super :: profiling (ir , runtime_context , counters , counter_queue)) ; insta :: assert_debug_snapshot ! (& pushed_down . ir ()) ; let _ = pushed_down . compile_no_network :: < MultiGraph > () ; } } } pub mod properties { pub use std :: collections :: HashSet ; pub use stageleft :: * ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , SeenTees } ; pub use crate :: properties :: PropertyDatabase ; # [doc = " Allows us to convert the hydroflow datatype for folds to a binary operation for the algebra"] # [doc = " property tests."] # [allow (dead_code)] pub fn convert_hf_to_binary < I , A : Default , F : Fn (& mut A , I) > (f : F) -> impl Fn (I , I) -> A { move | a , b | { let mut acc = Default :: default () ; f (& mut acc , a) ; f (& mut acc , b) ; acc } } # [cfg (stageleft_macro)] impl PropertyDatabase { # [doc = " Tags the expression as commutative."] pub fn add_commutative_tag < 'a , I , A , F : Fn (& mut A , I) , Q : Quoted < 'a , F > + Clone > (& mut self , expr : Q ,) -> Q { let expr_clone = expr . clone () ; self . commutative . insert (expr_clone . splice ()) ; expr } pub fn is_tagged_commutative (& self , expr : & syn :: Expr) -> bool { self . commutative . contains (expr) } } pub fn properties_optimize_node < 'a > (node : & mut HfPlusNode < 'a > , db : & PropertyDatabase , seen_tees : & mut SeenTees < 'a > ,) { node . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , seen_tees ,) ; match node { HfPlusNode :: ReduceKeyed { f , .. } if db . is_tagged_commutative (& f . 0) => { dbg ! ("IDENTIFIED COMMUTATIVE OPTIMIZATION for {:?}" , & f) ; } _ => { } } } pub fn properties_optimize < 'a > (ir : Vec < HfPlusLeaf < 'a > > , db : & PropertyDatabase ,) -> Vec < HfPlusLeaf < 'a > > { let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use super :: * ; use crate :: deploy :: SingleProcessGraph ; use crate :: FlowBuilder ; # [test] fn test_property_database () { let mut db = PropertyDatabase :: default () ; assert ! (! db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; let _ = db . add_commutative_tag (q ! (| a : & mut i32 , b : i32 | * a += b)) ; assert ! (db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; } # [test] fn test_property_optimized () { let flow = FlowBuilder :: new () ; let mut database = PropertyDatabase :: default () ; let process = flow . process :: < () > () ; let counter_func = q ! (| count : & mut i32 , _ | * count += 1) ; let _ = database . add_commutative_tag (counter_func) ; flow . source_iter (& process , q ! (vec ! [])) . map (q ! (| string : String | (string , ()))) . tick_batch () . fold_keyed (q ! (|| 0) , counter_func) . all_ticks () . for_each (q ! (| (string , count) | println ! ("{}: {}" , string , count))) ; let built = flow . finalize () . optimize_with (| ir | properties_optimize (ir , & database)) . with_default_optimize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let _ = built . compile_no_network :: < SingleProcessGraph > () ; } } } pub use crate :: RuntimeContext ; # [cfg (stageleft_macro)] impl Copy for RuntimeContext < '_ > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Context > for RuntimeContext < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (quote ! (& context))) } } pub use crate :: HfCompiled ; # [cfg (stageleft_macro)] impl < 'a , ID > HfCompiled < 'a , ID > { pub fn hydroflow_ir (& self) -> & BTreeMap < usize , HydroflowGraph > { & self . hydroflow_ir } } # [cfg (stageleft_macro)] impl < 'a > HfCompiled < 'a , usize > { pub fn with_dynamic_id (self , id : impl Quoted < 'a , usize >) -> HfBuiltWithId < 'a > { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; let mut conditioned_tokens = None ; for (subgraph_id , flat_graph) in self . hydroflow_ir { let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; let my_extra_stmts = self . extra_stmts . get (& subgraph_id) . cloned () . unwrap_or_default () ; if let Some (conditioned_tokens) = conditioned_tokens . as_mut () { * conditioned_tokens = syn :: parse_quote ! { # conditioned_tokens else if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } } ; } else { conditioned_tokens = Some (syn :: parse_quote ! { if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } }) ; } } let conditioned_tokens : TokenStream = conditioned_tokens . unwrap () ; let id = id . splice () ; HfBuiltWithId { tokens : syn :: parse_quote ! ({ let __given_id = # id ; # conditioned_tokens else { panic ! ("Invalid node id: {}" , __given_id) ; } }) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfCompiled < 'a , () > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfCompiled < 'a , () > { fn to_tokens (mut self) -> (Option < TokenStream > , Option < TokenStream >) { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; if self . hydroflow_ir . len () != 1 { panic ! ("Expected exactly one subgraph in the Hydroflow IR") ; } let flat_graph = self . hydroflow_ir . remove (& 0) . unwrap () ; let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; (None , Some (tokens)) } } pub use crate :: HfBuiltWithId ; # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfBuiltWithId < 'a > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfBuiltWithId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (self . tokens)) } }
[INFO] [stdout] 1 + pub use std :: collections :: BTreeMap ; pub use std :: marker :: PhantomData ; pub use hydroflow :: scheduled :: context :: Context ; pub use hydroflow :: scheduled :: graph :: Hydroflow ; pub use hydroflow :: * ; pub use lang :: graph :: { partition_graph , HydroflowGraph } ; pub use proc_macro2 :: TokenStream ; pub use quote :: quote ; pub use stageleft :: runtime_support :: FreeVariable ; pub use stageleft :: Quoted ; pub mod runtime_support { pub use bincode ; } pub mod stream { pub use std :: cell :: RefCell ; pub use std :: hash :: Hash ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow :: bytes :: Bytes ; pub use hydroflow :: futures :: Sink ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: quote ; pub use serde :: de :: DeserializeOwned ; pub use serde :: Serialize ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use syn :: parse_quote ; pub use crate :: builder :: { ClusterIds , FlowLeaves } ; pub use crate :: cycle :: { CycleCollection , CycleComplete } ; pub use crate :: ir :: { DebugInstantiate , HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { CanSend , Location , LocationId } ; pub use crate :: { Cluster , Optional , Singleton } ; pub use crate :: stream :: Unbounded ; pub use crate :: stream :: Bounded ; pub use crate :: stream :: NoTick ; pub use crate :: stream :: Tick ; pub use crate :: stream :: Stream ; # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Stream { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Stream < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Stream { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , C , N > > ,) -> Stream < 'a , (T , O) , W , C , N > where O : Clone , { let other : Optional < 'a , O , Bounded , C , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn cross_product < O > (self , other : Stream < 'a , O , W , C , N >) -> Stream < 'a , (T , O) , W , C , N > where T : Clone , O : Clone , { if self . location_kind != other . location_kind { panic ! ("cross_product must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossProduct (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn union (self , other : Stream < 'a , T , W , C , N >) -> Stream < 'a , T , W , C , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn dest_sink < S : Unpin + Sink < T > + 'a > (self , sink : impl Quoted < 'a , S >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: DestSink { sink : sink . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn first (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } # [doc = " Allow this stream through if the other stream has elements, otherwise the output is empty."] pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } # [doc = " Allow this stream through if the other stream is empty, otherwise the output is empty."] pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn enumerate (self) -> Stream < 'a , (usize , T) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Enumerate (Box :: new (self . ir_node . into_inner ())) ,) } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn sort (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Ord , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Sort (Box :: new (self . ir_node . into_inner ())) ,) } pub fn count (self) -> Singleton < 'a , usize , Bounded , Tick , N > { self . fold (q ! (|| 0usize) , q ! (| count , _ | * count += 1)) } pub fn delta (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } pub fn unique (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Eq + Hash , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unique (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn tick_batch (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_prefix (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { self . tick_batch () . persist () } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn for_each < F : Fn (T) + 'a > (self , f : impl IntoQuotedMut < 'a , F >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: ForEach { input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , f : f . splice () . into () , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Unbounded , NoTick , N > { pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . tick_batch () . continue_if (samples . first ()) . all_ticks () } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Unbounded , NoTick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , C , N : Location > Stream < 'a , T , Bounded , C , N > { pub fn filter_not_in (self , other : Stream < 'a , T , Bounded , C , N >) -> Stream < 'a , T , Bounded , C , N > where T : Eq + Hash , { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Difference (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Stream < 'a , & T , W , C , N > { pub fn cloned (self) -> Stream < 'a , T , W , C , N > { self . map (q ! (| d | d . clone ())) } } # [cfg (stageleft_macro)] impl < 'a , K , V1 , W , C , N : Location > Stream < 'a , (K , V1) , W , C , N > { pub fn join < W2 , V2 > (self , n : Stream < 'a , (K , V2) , W2 , C , N > ,) -> Stream < 'a , (K , (V1 , V2)) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Join (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } pub fn anti_join < W2 > (self , n : Stream < 'a , K , W2 , C , N >) -> Stream < 'a , (K , V1) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("anti_join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: AntiJoin (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , K : Eq + Hash , V , N : Location > Stream < 'a , (K , V) , Bounded , Tick , N > { pub fn fold_keyed < A , I : Fn () -> A + 'a , F : Fn (& mut A , V) + 'a > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , A) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FoldKeyed { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce_keyed < F : Fn (& mut V , V) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , V) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: ReduceKeyed { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } pub fn get_this_crate () -> TokenStream { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , Span :: call_site ()) ; quote ! { # ident } } } } pub fn serialize_bincode < T : Serialize > (is_demux : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if is_demux { parse_quote ! { map (| (id , data) | { (id , # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into ()) }) } } else { parse_quote ! { map (| data | { # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into () }) } } } pub fn deserialize_bincode < T : DeserializeOwned > (tagged : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if tagged { parse_quote ! { map (| res | { let (id , b) = res . unwrap () ; (id , # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& b) . unwrap ()) }) } } else { parse_quote ! { map (| res | { # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& res . unwrap ()) . unwrap () }) } } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn send_bincode < N2 : Location , CoreType > (self , other : & N2 ,) -> Stream < 'a , N :: Out < CoreType > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T > , CoreType : Serialize + DeserializeOwned , { let serialize_pipeline = Some (serialize_bincode :: < CoreType > (N :: is_demux ())) ; let deserialize_pipeline = Some (deserialize_bincode :: < CoreType > (N :: is_tagged ())) ; Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bytes < N2 : Location > (self , other : & N2 ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T > , { Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline : None , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline : if N :: is_tagged () { Some (parse_quote ! (map (| (id , b) | (id , b . unwrap () . freeze ())))) } else { Some (parse_quote ! (map (| b | b . unwrap () . freeze ()))) } , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bincode_interleaved < N2 : Location , Tag , CoreType > (self , other : & N2 ,) -> Stream < 'a , CoreType , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T , Out < CoreType > = (Tag , CoreType) > , CoreType : Serialize + DeserializeOwned , { self . send_bincode :: < N2 , CoreType > (other) . map (q ! (| (_ , b) | b)) } pub fn send_bytes_interleaved < N2 : Location , Tag > (self , other : & N2 ,) -> Stream < 'a , Bytes , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T , Out < Bytes > = (Tag , Bytes) > , { self . send_bytes :: < N2 > (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bincode < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < T > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) > , T : Clone + Serialize + DeserializeOwned , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bincode (other) } pub fn broadcast_bincode_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , T , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) , Out < T > = (Tag , T) > + 'a , T : Clone + Serialize + DeserializeOwned , { self . broadcast_bincode (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bytes < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) > + 'a , T : Clone , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bytes (other) } pub fn broadcast_bytes_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , Bytes , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) , Out < Bytes > = (Tag , Bytes) > + 'a , T : Clone , { self . broadcast_bytes (other) . map (q ! (| (_ , b) | b)) } } } pub use stream :: { Bounded , NoTick , Stream , Tick , Unbounded } ; pub mod singleton { pub use std :: cell :: RefCell ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use crate :: builder :: FlowLeaves ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial , CycleComplete } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: Stream ; pub use crate :: singleton :: CrossResult ; # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Singleton < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Singleton :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } pub use crate :: singleton :: Singleton ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Singleton { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleComplete < 'a > for Singleton < 'a , T , Bounded , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleCollectionWithInitial < 'a > for Singleton < 'a , T , Bounded , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , initial : Self , l : LocationId ,) -> Self { Singleton :: new (l , ir_leaves , HfPlusNode :: Union (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , }) , initial . ir_node . into_inner () . into () ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Singleton < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Singleton { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , U , W , C , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (Self :: other_ir_node (other)) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Singleton < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CrossSingleton (Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , Box :: new (HfPlusNode :: Unpersist (Box :: new (Self :: other_ir_node (other)))) ,))) ,) } } pub use crate :: singleton :: Optional ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Optional { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } pub fn some (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: new (singleton . location_kind , singleton . ir_leaves , singleton . ir_node . into_inner () ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > From < Singleton < 'a , T , W , C , N > > for Optional < 'a , T , W , C , N > { fn from (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: some (singleton) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Optional < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Optional { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn into_stream (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , Tick , N > > ,) -> Optional < 'a , (T , O) , Bounded , Tick , N > where O : Clone , { let other : Optional < 'a , O , Bounded , Tick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn union (self , other : Optional < 'a , T , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Optional < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_samples (self) -> Stream < 'a , T , Unbounded , NoTick , N > { self . latest_tick () . all_ticks () } pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . latest_tick () . continue_if (samples . first ()) . latest () . tick_samples () } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Unbounded , NoTick , N > > ,) -> Optional < 'a , (T , O) , Unbounded , NoTick , N > where O : Clone , { let other : Optional < 'a , O , Unbounded , NoTick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } self . latest_tick () . cross_singleton (other . latest_tick ()) . latest () } } } pub use singleton :: { Optional , Singleton } ; pub mod location { pub use std :: marker :: PhantomData ; pub use crate :: location :: LocationId ; pub use crate :: location :: Location ; pub use crate :: location :: Process ; # [cfg (stageleft_macro)] impl < P > Clone for Process < P > { fn clone (& self) -> Self { Process { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < P > Location for Process < P > { fn id (& self) -> LocationId { LocationId :: Process (self . id) } } pub use crate :: location :: Cluster ; # [cfg (stageleft_macro)] impl < C > Clone for Cluster < C > { fn clone (& self) -> Self { Cluster { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < C > Location for Cluster < C > { fn id (& self) -> LocationId { LocationId :: Cluster (self . id) } } pub use crate :: location :: CanSend ; # [cfg (stageleft_macro)] impl < P1 , P2 > CanSend < Process < P2 > > for Process < P1 > { type In < T > = T ; type Out < T > = T ; fn is_demux () -> bool { false } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < P1 , C2 > CanSend < Cluster < C2 > > for Process < P1 > { type In < T > = (u32 , T) ; type Out < T > = T ; fn is_demux () -> bool { true } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < C1 , P2 > CanSend < Process < P2 > > for Cluster < C1 > { type In < T > = T ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { false } fn is_tagged () -> bool { true } } # [cfg (stageleft_macro)] impl < C1 , C2 > CanSend < Cluster < C2 > > for Cluster < C1 > { type In < T > = (u32 , T) ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { true } fn is_tagged () -> bool { true } } } pub use location :: { Cluster , Process } ; pub mod deploy { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use stageleft :: Quoted ; pub mod graphs { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use super :: { LocalDeploy , Node , ProcessSpec } ; pub use crate :: deploy :: graphs :: SingleProcessGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for SingleProcessGraph { type Process = SingleNode ; type Cluster = SingleNode ; type Meta = () ; type GraphId = () ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { SingleNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { SingleNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , SingleProcessGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> SingleNode { SingleNode { } } } pub use crate :: deploy :: graphs :: SingleNode ; # [cfg (stageleft_macro)] impl Node for SingleNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } pub use crate :: deploy :: graphs :: MultiGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for MultiGraph { type Process = MultiNode ; type Cluster = MultiNode ; type Meta = () ; type GraphId = usize ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { MultiNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { MultiNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , MultiGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> MultiNode { MultiNode { } } } pub use crate :: deploy :: graphs :: MultiNode ; # [cfg (stageleft_macro)] impl Node for MultiNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } } pub use graphs :: * ; pub use crate :: deploy :: LocalDeploy ; pub use crate :: deploy :: Deploy ; # [cfg (stageleft_macro)] impl < 'a , T : Deploy < 'a , Process = N , Cluster = C , Meta = M , GraphId = R > , N : Node < Meta = M > , C : Node < Meta = M > , M : Default , R , > LocalDeploy < 'a > for T { type Process = N ; type Cluster = C ; type Meta = M ; type GraphId = R ; fn has_trivial_node () -> bool { < T as Deploy < 'a > > :: has_trivial_node () } fn trivial_process (id : usize) -> Self :: Process { < T as Deploy < 'a > > :: trivial_process (id) } fn trivial_cluster (id : usize) -> Self :: Cluster { < T as Deploy < 'a > > :: trivail_cluster (id) } } pub use crate :: deploy :: ProcessSpec ; pub use crate :: deploy :: ClusterSpec ; pub use crate :: deploy :: Node ; } pub use deploy :: { ClusterSpec , Deploy , ProcessSpec } ; pub mod cycle { pub use std :: marker :: PhantomData ; pub use crate :: builder :: FlowLeaves ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: cycle :: CycleComplete ; pub use crate :: cycle :: CycleCollection ; pub use crate :: cycle :: CycleCollectionWithInitial ; pub use crate :: cycle :: HfCycle ; # [cfg (stageleft_macro)] impl < 'a , S : CycleComplete < 'a > > HfCycle < 'a , S > { pub fn complete (self , stream : S) { let ident = self . ident ; S :: complete (stream , ident) } } } pub use cycle :: HfCycle ; pub mod builder { pub use std :: cell :: RefCell ; pub use std :: collections :: HashMap ; pub use std :: marker :: PhantomData ; pub use std :: rc :: Rc ; pub use std :: time :: Duration ; pub use hydroflow :: futures :: stream :: Stream as FuturesStream ; pub use hydroflow :: { tokio , tokio_stream } ; pub use internal :: TokenStream ; pub use proc_macro2 :: Span ; pub use quote :: quote ; pub use runtime_support :: FreeVariable ; pub use stageleft :: * ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Cluster , Location , LocationId , Process } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: { HfCycle , Optional , RuntimeContext , Singleton , Stream } ; pub mod built { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use hydroflow_lang :: graph :: { eliminate_extra_unions_tees , HydroflowGraph } ; pub use super :: deploy :: { DeployFlow , DeployResult } ; pub use crate :: deploy :: { ClusterSpec , Deploy , LocalDeploy , ProcessSpec } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Cluster , Process } ; pub use crate :: HfCompiled ; pub use crate :: builder :: built :: BuiltFlow ; # [cfg (stageleft_macro)] impl < 'a > Drop for BuiltFlow < 'a > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped BuiltFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn ir (& self) -> & Vec < HfPlusLeaf < 'a > > { & self . ir } pub fn optimize_with (mut self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> BuiltFlow < 'a > { self . used = true ; BuiltFlow { ir : f (std :: mem :: take (& mut self . ir)) , processes : std :: mem :: take (& mut self . processes) , clusters : std :: mem :: take (& mut self . clusters) , used : false , _phantom : PhantomData , } } } pub fn build_inner (ir : & mut Vec < HfPlusLeaf >) -> BTreeMap < usize , HydroflowGraph > { let mut builders = BTreeMap :: new () ; let mut built_tees = HashMap :: new () ; let mut next_stmt_id = 0 ; for leaf in ir { leaf . emit (& mut builders , & mut built_tees , & mut next_stmt_id) ; } builders . into_iter () . map (| (k , v) | { let (mut flat_graph , _ , _) = v . build () ; eliminate_extra_unions_tees (& mut flat_graph) ; (k , flat_graph) }) . collect () } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn compile_no_network < D : LocalDeploy < 'a > > (mut self) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; HfCompiled { hydroflow_ir : build_inner (& mut self . ir) , extra_stmts : BTreeMap :: new () , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> BuiltFlow < 'a > { self . optimize_with (crate :: persist_pullup :: persist_pullup) } fn into_deploy < D : LocalDeploy < 'a > > (mut self) -> DeployFlow < 'a , D > { self . used = true ; let processes = if D :: has_trivial_node () { self . processes . iter () . map (| id | (* id , D :: trivial_process (* id))) . collect () } else { HashMap :: new () } ; let clusters = if D :: has_trivial_node () { self . clusters . iter () . map (| id | (* id , D :: trivial_cluster (* id))) . collect () } else { HashMap :: new () } ; DeployFlow { ir : std :: mem :: take (& mut self . ir) , nodes : processes , clusters , used : false , _phantom : PhantomData , } } pub fn with_process < P , D : LocalDeploy < 'a > > (self , process : & Process < P > , spec : impl ProcessSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_process (process , spec) } pub fn with_cluster < C , D : LocalDeploy < 'a > > (self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_cluster (cluster , spec) } pub fn compile < D : Deploy < 'a > + 'a > (self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . into_deploy :: < D > () . compile (env) } pub fn deploy < D : Deploy < 'a , CompileEnv = () > + 'a > (self , env : & mut D :: InstantiateEnv ,) -> DeployResult < 'a , D > { self . into_deploy :: < D > () . deploy (env) } } } pub mod deploy { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use proc_macro2 :: Span ; pub use stageleft :: Quoted ; pub use super :: built :: build_inner ; pub use crate :: deploy :: { LocalDeploy , Node } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: { Cluster , ClusterSpec , Deploy , HfCompiled , Process , ProcessSpec } ; pub use crate :: builder :: deploy :: DeployFlow ; # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > Drop for DeployFlow < 'a , D > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped DeployFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > DeployFlow < 'a , D > { pub fn with_process < P > (mut self , process : & Process < P > , spec : impl ProcessSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < P > () . to_string () ; self . nodes . insert (process . id , spec . build (process . id , & tag_name)) ; self } pub fn with_cluster < C > (mut self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < C > () . to_string () ; self . clusters . insert (cluster . id , spec . build (cluster . id , & tag_name)) ; self } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployFlow < 'a , D > { pub fn compile (mut self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; let mut seen_tees : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | leaf . compile_network :: < D > (env , & mut seen_tees , & self . nodes , & self . clusters)) . collect () ; let extra_stmts = self . extra_stmts (env) ; HfCompiled { hydroflow_ir : build_inner (& mut ir_leaves_networked) , extra_stmts , _phantom : PhantomData , } } fn extra_stmts (& self , env : & < D as Deploy < 'a > > :: CompileEnv) -> BTreeMap < usize , Vec < syn :: Stmt > > { let all_locations_count = self . nodes . len () + self . clusters . len () ; let mut extra_stmts : BTreeMap < usize , Vec < syn :: Stmt > > = BTreeMap :: new () ; for & c_id in self . clusters . keys () { let self_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , c_id) , Span :: call_site () ,) ; let self_id_expr = D :: cluster_self_id (env) . splice () ; extra_stmts . entry (c_id) . or_default () . push (syn :: parse_quote ! { let # self_id_ident = # self_id_expr ; }) ; for other_location in 0 .. all_locations_count { let other_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , c_id) , Span :: call_site () ,) ; let other_id_expr = D :: cluster_ids (env , c_id) . splice () ; extra_stmts . entry (other_location) . or_default () . push (syn :: parse_quote ! { let # other_id_ident = # other_id_expr ; }) ; } } extra_stmts } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a , CompileEnv = () > > DeployFlow < 'a , D > { # [must_use] pub fn deploy (mut self , env : & mut D :: InstantiateEnv) -> DeployResult < 'a , D > { self . used = true ; let mut seen_tees_instantiate : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | { leaf . compile_network :: < D > (& () , & mut seen_tees_instantiate , & self . nodes , & self . clusters ,) }) . collect () ; let mut compiled = build_inner (& mut ir_leaves_networked) ; let mut extra_stmts = self . extra_stmts (& ()) ; let mut meta = D :: Meta :: default () ; let (mut processes , mut clusters) = (std :: mem :: take (& mut self . nodes) . into_iter () . map (| (node_id , node) | { node . instantiate (env , & mut meta , compiled . remove (& node_id) . unwrap () , extra_stmts . remove (& node_id) . unwrap_or_default () ,) ; (node_id , node) }) . collect :: < HashMap < _ , _ > > () , std :: mem :: take (& mut self . clusters) . into_iter () . map (| (cluster_id , cluster) | { cluster . instantiate (env , & mut meta , compiled . remove (& cluster_id) . unwrap () , extra_stmts . remove (& cluster_id) . unwrap_or_default () ,) ; (cluster_id , cluster) }) . collect :: < HashMap < _ , _ > > () ,) ; for node in processes . values_mut () { node . update_meta (& meta) ; } for cluster in clusters . values_mut () { cluster . update_meta (& meta) ; } let mut seen_tees_connect = HashMap :: new () ; for leaf in ir_leaves_networked { leaf . connect_network (& mut seen_tees_connect) ; } DeployResult { processes , clusters , } } } pub use crate :: builder :: deploy :: DeployResult ; # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployResult < 'a , D > { pub fn get_process < P > (& self , p : & Process < P >) -> & D :: Process { let id = match p . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . processes . get (& id) . unwrap () } pub fn get_cluster < C > (& self , c : & Cluster < C >) -> & D :: Cluster { let id = match c . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . clusters . get (& id) . unwrap () } } } # [doc = " Tracks the leaves of the dataflow IR. This is referenced by"] # [doc = " `Stream` and `HfCycle` to build the IR. The inner option will"] # [doc = " be set to `None` when this builder is finalized."] pub type FlowLeaves < 'a > = Rc < RefCell < Option < Vec < HfPlusLeaf < 'a > > > > > ; pub use crate :: builder :: ClusterIds ; # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Vec < u32 > > for ClusterIds < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , & 'a Vec < u32 > > for ClusterIds < 'a > { } # [derive (Copy , Clone)] pub struct ClusterSelfId < 'a > { pub id : usize , pub _phantom : PhantomData < & 'a mut & 'a u32 > , } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < u32 > for ClusterSelfId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , u32 > for ClusterSelfId < 'a > { } pub use crate :: builder :: FlowBuilder ; # [cfg (stageleft_macro)] impl < 'a > Drop for FlowBuilder < 'a > { fn drop (& mut self) { if ! self . finalized { panic ! ("Dropped FlowBuilder without finalizing, you may have forgotten to call `with_default_optimize`, `optimize_with`, or `finalize`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > QuotedContext for FlowBuilder < 'a > { fn create () -> Self { FlowBuilder :: new () } } # [cfg (stageleft_macro)] impl < 'a > FlowBuilder < 'a > { # [allow (clippy :: new_without_default)] pub fn new () -> FlowBuilder < 'a > { FlowBuilder { ir_leaves : Rc :: new (RefCell :: new (Some (Vec :: new ()))) , nodes : RefCell :: new (vec ! []) , clusters : RefCell :: new (vec ! []) , cycle_ids : RefCell :: new (HashMap :: new ()) , next_node_id : RefCell :: new (0) , finalized : false , _phantom : PhantomData , } } pub fn finalize (mut self) -> built :: BuiltFlow < 'a > { self . finalized = true ; built :: BuiltFlow { ir : self . ir_leaves . borrow_mut () . take () . unwrap () , processes : self . nodes . replace (vec ! []) , clusters : self . clusters . replace (vec ! []) , used : false , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> built :: BuiltFlow < 'a > { self . finalize () . with_default_optimize () } pub fn optimize_with (self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> built :: BuiltFlow < 'a > { self . finalize () . optimize_with (f) } pub fn ir_leaves (& self) -> & FlowLeaves < 'a > { & self . ir_leaves } pub fn process < P > (& self) -> Process < P > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . nodes . borrow_mut () . push (id) ; Process { id , _phantom : PhantomData , } } pub fn cluster < C > (& self) -> Cluster < C > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . clusters . borrow_mut () . push (id) ; Cluster { id , _phantom : PhantomData , } } pub fn runtime_context (& self) -> RuntimeContext < 'a > { RuntimeContext { _phantom : PhantomData , } } pub fn cluster_members < C > (& self , cluster : & Cluster < C > ,) -> impl Quoted < 'a , & 'a Vec < u32 > > + Copy + 'a { ClusterIds { id : cluster . id , _phantom : PhantomData , } } pub fn cluster_self_id < C > (& self , cluster : & Cluster < C >) -> impl Quoted < 'a , u32 > + Copy + 'a { ClusterSelfId { id : cluster . id , _phantom : PhantomData , } } pub fn spin < L : Location > (& self , on : & L) -> Stream < 'a , () , Unbounded , NoTick , L > { Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Spin () , location_kind : on . id () , })) ,) } pub fn spin_batch < L : Location > (& self , on : & L , batch_size : impl Quoted < 'a , usize > + Copy + 'a ,) -> Stream < 'a , () , Bounded , Tick , L > { self . spin (on) . flat_map (q ! (move | _ | 0 .. batch_size)) . map (q ! (| _ | ())) . tick_batch () } pub fn source_stream < T , E : FuturesStream < Item = T > + Unpin , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Unbounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Stream (e . into ()) , location_kind : on . id () , })) ,) } pub fn source_iter < T , E : IntoIterator < Item = T > , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Bounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , })) ,) } pub fn singleton < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Singleton < 'a , T , Bounded , NoTick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Singleton :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,)))) ,) } pub fn singleton_first_tick < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Optional < 'a , T , Bounded , Tick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,) } pub fn source_interval < L : Location > (& self , on : & L , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , () , Unbounded , NoTick , L > { let interval = interval . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : on . id () , })) ,) } pub fn source_interval_delayed < L : Location > (& self , on : & L , delay : impl Quoted < 'a , Duration > + Copy + 'a , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , tokio :: time :: Instant , Unbounded , NoTick , L > { self . source_stream (on , q ! (tokio_stream :: wrappers :: IntervalStream :: new (tokio :: time :: interval_at (tokio :: time :: Instant :: now () + delay , interval))) ,) . tick_batch () . first () . latest () } pub fn cycle < S : CycleCollection < 'a > > (& self , on : & S :: Location) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , on . id ()) ,) } pub fn cycle_with_initial < S : CycleCollectionWithInitial < 'a > > (& self , on : & S :: Location , initial : S ,) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , initial , on . id ()) ,) } } } pub use builder :: FlowBuilder ; pub mod ir { pub use core :: panic ; pub use std :: cell :: RefCell ; pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow_lang :: graph :: FlatGraphBuilder ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: ToTokens ; pub use syn :: parse_quote ; pub use crate :: deploy :: Deploy ; pub use crate :: location :: LocationId ; pub use crate :: ir :: DebugExpr ; # [cfg (stageleft_macro)] impl From < syn :: Expr > for DebugExpr { fn from (expr : syn :: Expr) -> DebugExpr { DebugExpr (expr) } } # [cfg (stageleft_macro)] impl Deref for DebugExpr { type Target = syn :: Expr ; fn deref (& self) -> & Self :: Target { & self . 0 } } # [cfg (stageleft_macro)] impl ToTokens for DebugExpr { fn to_tokens (& self , tokens : & mut TokenStream) { self . 0 . to_tokens (tokens) ; } } # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugExpr { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "{}" , self . 0 . to_token_stream ()) } } pub use crate :: ir :: DebugInstantiate ; # [cfg (stageleft_macro)] impl < 'a > std :: fmt :: Debug for DebugInstantiate < 'a > { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<network instantiate>") } } pub use crate :: ir :: DebugPipelineFn ; # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugPipelineFn { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<function>") } } pub use crate :: ir :: HfPlusSource ; pub use crate :: ir :: HfPlusLeaf ; # [cfg (stageleft_macro)] impl < 'a > HfPlusLeaf < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . compile_network :: < D > (compile_env , s , nodes , clusters) ; } , seen_tees ,) } pub fn connect_network (self , seen_tees : & mut SeenTees < 'a >) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . connect_network (s) ; } , seen_tees ,) } pub fn transform_children (self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) -> HfPlusLeaf < 'a > { match self { HfPlusLeaf :: ForEach { f , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: ForEach { f , input } } HfPlusLeaf :: DestSink { sink , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: DestSink { sink , input } } HfPlusLeaf :: CycleSink { ident , location_kind , mut input , } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: CycleSink { ident , location_kind , input , } } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) { match self { HfPlusLeaf :: ForEach { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> for_each (# f) ; }) ; } HfPlusLeaf :: DestSink { sink , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink) ; }) ; } HfPlusLeaf :: CycleSink { ident , location_kind , input , } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; assert_eq ! (input_location_id , * location_id , "cycle_sink location mismatch") ; graph_builders . entry (* location_id) . or_default () . add_statement (parse_quote ! { # ident = # input_ident ; }) ; } } } } pub use crate :: ir :: HfPlusNode ; pub type SeenTees < 'a > = HashMap < * const RefCell < HfPlusNode < 'a > > , Rc < RefCell < HfPlusNode < 'a > > > > ; # [cfg (stageleft_macro)] impl < 'a > HfPlusNode < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (& mut self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) { self . transform_children (| n , s | n . compile_network :: < D > (compile_env , s , nodes , clusters) , seen_tees ,) ; if let HfPlusNode :: Network { from_location , to_location , instantiate_fn , .. } = self { let (sink_expr , source_expr , connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { let ((sink , source) , connect_fn) = match (from_location , to_location) { (LocationId :: Process (from) , LocationId :: Process (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: o2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Process (from) , LocationId :: Cluster (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: o2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Process (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: m2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Cluster (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: m2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } } ; (sink , source , connect_fn) } DebugInstantiate :: Finalized (_ , _ , _) => panic ! ("network already finalized") , } ; * instantiate_fn = DebugInstantiate :: Finalized (sink_expr , source_expr , connect_fn) ; } } pub fn connect_network (& mut self , seen_tees : & mut SeenTees < 'a >) { self . transform_children (| n , s | n . connect_network (s) , seen_tees) ; if let HfPlusNode :: Network { instantiate_fn , .. } = self { match instantiate_fn { DebugInstantiate :: Building () => panic ! ("network not built") , DebugInstantiate :: Finalized (_ , _ , ref connect_fn) => { connect_fn () ; } } } } pub fn transform_children (& mut self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) { match self { HfPlusNode :: Placeholder => { panic ! () ; } HfPlusNode :: Source { .. } => { } HfPlusNode :: CycleSource { .. } => { } HfPlusNode :: Tee { inner } => { if let Some (transformed) = seen_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { * inner = transformed . clone () ; } else { let transformed_cell = Rc :: new (RefCell :: new (HfPlusNode :: Placeholder)) ; seen_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , transformed_cell . clone () ,) ; let mut orig = inner . replace (HfPlusNode :: Placeholder) ; transform (& mut orig , seen_tees) ; * transformed_cell . borrow_mut () = orig ; * inner = transformed_cell ; } } HfPlusNode :: Persist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Unpersist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Delta (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Union (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossProduct (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossSingleton (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Join (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Difference (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: AntiJoin (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Map { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FlatMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Filter { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FilterMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Sort (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: DeferTick (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Enumerate (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Inspect { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Unique (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Fold { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FoldKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Reduce { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: ReduceKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Network { input , .. } => { transform (input . as_mut () , seen_tees) ; } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) -> (syn :: Ident , usize) { match self { HfPlusNode :: Placeholder => { panic ! () } HfPlusNode :: Persist (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let persist_id = * next_stmt_id ; * next_stmt_id += 1 ; let persist_ident = syn :: Ident :: new (& format ! ("stream_{}" , persist_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # persist_ident = # inner_ident -> persist ::<'static > () ; }) ; (persist_ident , location) } HfPlusNode :: Unpersist (_) => { panic ! ("Unpersist is a marker node and should have been optimized away. This is likely a compiler bug.") } HfPlusNode :: Delta (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let delta_id = * next_stmt_id ; * next_stmt_id += 1 ; let delta_ident = syn :: Ident :: new (& format ! ("stream_{}" , delta_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # delta_ident = # inner_ident -> multiset_delta () ; }) ; (delta_ident , location) } HfPlusNode :: Source { source , location_kind , } => { let source_id = * next_stmt_id ; * next_stmt_id += 1 ; let source_ident = syn :: Ident :: new (& format ! ("stream_{}" , source_id) , Span :: call_site ()) ; let source_stmt = match source { HfPlusSource :: Stream (expr) => { parse_quote ! { # source_ident = source_stream (# expr) ; } } HfPlusSource :: Iter (expr) => { parse_quote ! { # source_ident = source_iter (# expr) ; } } HfPlusSource :: Interval (expr) => { parse_quote ! { # source_ident = source_interval (# expr) ; } } HfPlusSource :: Spin () => { parse_quote ! { # source_ident = spin () ; } } } ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; graph_builders . entry (* location_id) . or_default () . add_statement (source_stmt) ; (source_ident , * location_id) } HfPlusNode :: CycleSource { ident , location_kind , } => { let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; (ident . clone () , * location_id) } HfPlusNode :: Tee { inner } => { if let Some (ret) = built_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { ret . clone () } else { let (inner_ident , inner_location_id) = inner . borrow () . emit (graph_builders , built_tees , next_stmt_id) ; let tee_id = * next_stmt_id ; * next_stmt_id += 1 ; let tee_ident = syn :: Ident :: new (& format ! ("stream_{}" , tee_id) , Span :: call_site ()) ; let builder = graph_builders . entry (inner_location_id) . or_default () ; builder . add_statement (parse_quote ! { # tee_ident = # inner_ident -> tee () ; }) ; built_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , (tee_ident . clone () , inner_location_id) ,) ; (tee_ident , inner_location_id) } } HfPlusNode :: Union (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "union inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let union_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # union_ident = union () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [0] # union_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # union_ident ; }) ; (union_ident , left_location_id) } HfPlusNode :: CrossSingleton (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "cross_singleton inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let cross_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # cross_ident = cross_singleton () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [input] # cross_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [single] # cross_ident ; }) ; (cross_ident , left_location_id) } HfPlusNode :: CrossProduct (..) | HfPlusNode :: Join (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: CrossProduct (..)) { parse_quote ! (cross_join_multiset) } else { parse_quote ! (join_multiset) } ; let (HfPlusNode :: CrossProduct (left , right) | HfPlusNode :: Join (left , right)) = self else { unreachable ! () } ; let (left_inner , left_was_persist) = if let HfPlusNode :: Persist (left) = left . as_ref () { (left , true) } else { (left , false) } ; let (right_inner , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left_inner . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right_inner . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "join / cross product inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; match (left_was_persist , right_was_persist) { (true , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'static > () ; }) ; } (true , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'tick > () ; }) ; } (false , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } (false , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } } ; builder . add_statement (parse_quote ! { # left_ident -> [0] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Difference (..) | HfPlusNode :: AntiJoin (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Difference (..)) { parse_quote ! (difference_multiset) } else { parse_quote ! (anti_join_multiset) } ; let (HfPlusNode :: Difference (left , right) | HfPlusNode :: AntiJoin (left , right)) = self else { unreachable ! () } ; let (right , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "difference / anti join inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; if right_was_persist { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } else { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } builder . add_statement (parse_quote ! { # left_ident -> [pos] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [neg] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Map { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let map_id = * next_stmt_id ; * next_stmt_id += 1 ; let map_ident = syn :: Ident :: new (& format ! ("stream_{}" , map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # map_ident = # input_ident -> map (# f) ; }) ; (map_ident , input_location_id) } HfPlusNode :: FlatMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let flat_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let flat_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , flat_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # flat_map_ident = # input_ident -> flat_map (# f) ; }) ; (flat_map_ident , input_location_id) } HfPlusNode :: Filter { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_ident = # input_ident -> filter (# f) ; }) ; (filter_ident , input_location_id) } HfPlusNode :: FilterMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_map_ident = # input_ident -> filter_map (# f) ; }) ; (filter_map_ident , input_location_id) } HfPlusNode :: Sort (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sort_id = * next_stmt_id ; * next_stmt_id += 1 ; let sort_ident = syn :: Ident :: new (& format ! ("stream_{}" , sort_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # sort_ident = # input_ident -> sort () ; }) ; (sort_ident , input_location_id) } HfPlusNode :: DeferTick (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let defer_tick_id = * next_stmt_id ; * next_stmt_id += 1 ; let defer_tick_ident = syn :: Ident :: new (& format ! ("stream_{}" , defer_tick_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # defer_tick_ident = # input_ident -> defer_tick_lazy () ; }) ; (defer_tick_ident , input_location_id) } HfPlusNode :: Enumerate (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let enumerate_id = * next_stmt_id ; * next_stmt_id += 1 ; let enumerate_ident = syn :: Ident :: new (& format ! ("stream_{}" , enumerate_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # enumerate_ident = # input_ident -> enumerate () ; }) ; (enumerate_ident , input_location_id) } HfPlusNode :: Inspect { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let inspect_id = * next_stmt_id ; * next_stmt_id += 1 ; let inspect_ident = syn :: Ident :: new (& format ! ("stream_{}" , inspect_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # inspect_ident = # input_ident -> inspect (# f) ; }) ; (inspect_ident , input_location_id) } HfPlusNode :: Unique (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let unique_id = * next_stmt_id ; * next_stmt_id += 1 ; let unique_ident = syn :: Ident :: new (& format ! ("stream_{}" , unique_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # unique_ident = # input_ident -> unique ::<'tick > () ; }) ; (unique_ident , input_location_id) } HfPlusNode :: Fold { .. } | HfPlusNode :: FoldKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Fold { .. }) { parse_quote ! (fold) } else { parse_quote ! (fold_keyed) } ; let (HfPlusNode :: Fold { init , acc , input } | HfPlusNode :: FoldKeyed { init , acc , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let fold_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'static > (# init , # acc) ; }) ; } else { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'tick > (# init , # acc) ; }) ; } (fold_ident , input_location_id) } HfPlusNode :: Reduce { .. } | HfPlusNode :: ReduceKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Reduce { .. }) { parse_quote ! (reduce) } else { parse_quote ! (reduce_keyed) } ; let (HfPlusNode :: Reduce { f , input } | HfPlusNode :: ReduceKeyed { f , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let reduce_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'static > (# f) ; }) ; } else { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'tick > (# f) ; }) ; } (reduce_ident , input_location_id) } HfPlusNode :: Network { from_location : _ , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input , } => { let (sink_expr , source_expr , _connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { panic ! ("Expected the network to be finalized") } DebugInstantiate :: Finalized (sink , source , connect_fn) => { (sink , source , connect_fn) } } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sender_builder = graph_builders . entry (input_location_id) . or_default () ; if let Some (serialize_pipeline) = serialize_pipeline { sender_builder . add_statement (parse_quote ! { # input_ident -> # serialize_pipeline -> dest_sink (# sink_expr) ; }) ; } else { sender_builder . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink_expr) ; }) ; } let to_id = match to_location { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let receiver_builder = graph_builders . entry (* to_id) . or_default () ; let receiver_stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let receiver_stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , receiver_stream_id) , Span :: call_site ()) ; if let Some (deserialize_pipeline) = deserialize_pipeline { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) -> # deserialize_pipeline ; }) ; } else { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) ; }) ; } (receiver_stream_ident , * to_id) } } } } } pub mod persist_pullup { pub use std :: cell :: RefCell ; pub use std :: collections :: HashSet ; pub use std :: ops :: Deref ; pub use crate :: ir :: * ; pub fn persist_pullup_node < 'a > (node : & mut HfPlusNode < 'a > , seen_tees : & mut SeenTees < 'a > , persist_pulled_tees : & mut HashSet < * const RefCell < HfPlusNode < 'a > > > ,) { node . transform_children (| n , s | persist_pullup_node (n , s , persist_pulled_tees) , seen_tees ,) ; match node { HfPlusNode :: Unpersist (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Unpersist (box HfPlusNode :: Persist (behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Delta (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Delta (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Tee { inner } => { if persist_pulled_tees . contains (& (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >)) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } else { let inner_borrow = inner . borrow () ; if let HfPlusNode :: Persist (_) = inner_borrow . deref () { drop (inner_borrow) ; persist_pulled_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >) ; if let HfPlusNode :: Persist (box behind_persist) = inner . replace (HfPlusNode :: Placeholder) { * inner . borrow_mut () = behind_persist ; } else { unreachable ! () } * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } } } HfPlusNode :: Map { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Map { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Map { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: FlatMap { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: FlatMap { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: FlatMap { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Filter { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Filter { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Filter { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Network { input : box HfPlusNode :: Persist (_) , .. } => { if let HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Union (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Union (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Union (left , right))) ; } else { unreachable ! () } } HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: CrossProduct (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,) ,)))) ; } else { unreachable ! () } } HfPlusNode :: Join (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Join (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: Join (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,))))) ; } else { unreachable ! () } } _ => { } } } pub fn persist_pullup (ir : Vec < HfPlusLeaf >) -> Vec < HfPlusLeaf > { let mut seen_tees = Default :: default () ; let mut persist_pulled_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| n , s | persist_pullup_node (n , s , & mut persist_pulled_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn persist_pullup_through_map () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } # [test] fn persist_pullup_behind_tee () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; let before_tee = flow . source_iter (& process , q ! (0 .. 10)) . tick_batch () . persist () ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } } } pub mod profiler { pub use std :: cell :: RefCell ; pub use hydroflow :: futures :: channel :: mpsc :: UnboundedSender ; pub use stageleft :: * ; pub use crate as hydroflow_plus ; pub use crate :: ir :: * ; pub use crate :: RuntimeContext ; pub fn increment_counter (count : & mut u64) { * count += 1 ; } pub fn quoted_any_fn < 'a , F : Fn (& usize) + 'a , Q : IntoQuotedMut < 'a , F > > (q : Q) -> Q { q } # [doc = " Add a profiling node before each node to count the cardinality of its input"] pub fn add_profiling_node < 'a > (node : & mut HfPlusNode < 'a > , _context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > , id : & mut u32 , seen_tees : & mut SeenTees < 'a > ,) { let my_id = * id ; * id += 1 ; node . transform_children (| node , seen_tees | { add_profiling_node (node , _context , counters , counter_queue , id , seen_tees) } , seen_tees ,) ; let orig_node = std :: mem :: replace (node , HfPlusNode :: Placeholder) ; * node = HfPlusNode :: Inspect { f : quoted_any_fn (q ! ({ counter_queue . borrow () . unbounded_send ((my_id as usize , counters . borrow () [my_id as usize])) . unwrap () ; counters . borrow_mut () [my_id as usize] = 0 ; move | _ | { hydroflow_plus :: profiler :: increment_counter (& mut counters . borrow_mut () [my_id as usize] ,) ; } })) . splice () . into () , input : Box :: new (orig_node) , } } # [doc = " Count the cardinality of each input and periodically output to a file"] pub fn profiling < 'a > (ir : Vec < HfPlusLeaf < 'a > > , context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > ,) -> Vec < HfPlusLeaf < 'a > > { let mut id = 0 ; let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | { add_profiling_node (node , context , counters , counter_queue , & mut id , seen_tees) } , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn profiler_wrapping_all_operators () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let runtime_context = flow . runtime_context () ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (& built . ir ()) ; let counters = RuntimeData :: new ("Fake") ; let counter_queue = RuntimeData :: new ("Fake") ; let pushed_down = built . with_default_optimize () . optimize_with (| ir | super :: profiling (ir , runtime_context , counters , counter_queue)) ; insta :: assert_debug_snapshot ! (& pushed_down . ir ()) ; let _ = pushed_down . compile_no_network :: < MultiGraph > () ; } } } pub mod properties { pub use std :: collections :: HashSet ; pub use stageleft :: * ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , SeenTees } ; pub use crate :: properties :: PropertyDatabase ; # [doc = " Allows us to convert the hydroflow datatype for folds to a binary operation for the algebra"] # [doc = " property tests."] # [allow (dead_code)] pub fn convert_hf_to_binary < I , A : Default , F : Fn (& mut A , I) > (f : F) -> impl Fn (I , I) -> A { move | a , b | { let mut acc = Default :: default () ; f (& mut acc , a) ; f (& mut acc , b) ; acc } } # [cfg (stageleft_macro)] impl PropertyDatabase { # [doc = " Tags the expression as commutative."] pub fn add_commutative_tag < 'a , I , A , F : Fn (& mut A , I) , Q : Quoted < 'a , F > + Clone > (& mut self , expr : Q ,) -> Q { let expr_clone = expr . clone () ; self . commutative . insert (expr_clone . splice ()) ; expr } pub fn is_tagged_commutative (& self , expr : & syn :: Expr) -> bool { self . commutative . contains (expr) } } pub fn properties_optimize_node < 'a > (node : & mut HfPlusNode < 'a > , db : & PropertyDatabase , seen_tees : & mut SeenTees < 'a > ,) { node . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , seen_tees ,) ; match node { HfPlusNode :: ReduceKeyed { f , .. } if db . is_tagged_commutative (& f . 0) => { dbg ! ("IDENTIFIED COMMUTATIVE OPTIMIZATION for {:?}" , & f) ; } _ => { } } } pub fn properties_optimize < 'a > (ir : Vec < HfPlusLeaf < 'a > > , db : & PropertyDatabase ,) -> Vec < HfPlusLeaf < 'a > > { let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use super :: * ; use crate :: deploy :: SingleProcessGraph ; use crate :: FlowBuilder ; # [test] fn test_property_database () { let mut db = PropertyDatabase :: default () ; assert ! (! db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; let _ = db . add_commutative_tag (q ! (| a : & mut i32 , b : i32 | * a += b)) ; assert ! (db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; } # [test] fn test_property_optimized () { let flow = FlowBuilder :: new () ; let mut database = PropertyDatabase :: default () ; let process = flow . process :: < () > () ; let counter_func = q ! (| count : & mut i32 , _ | * count += 1) ; let _ = database . add_commutative_tag (counter_func) ; flow . source_iter (& process , q ! (vec ! [])) . map (q ! (| string : String | (string , ()))) . tick_batch () . fold_keyed (q ! (|| 0) , counter_func) . all_ticks () . for_each (q ! (| (string , count) | println ! ("{}: {}" , string , count))) ; let built = flow . finalize () . optimize_with (| ir | properties_optimize (ir , & database)) . with_default_optimize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let _ = built . compile_no_network :: < SingleProcessGraph > () ; } } } pub use crate :: RuntimeContext ; # [cfg (stageleft_macro)] impl Copy for RuntimeContext < '_ > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Context > for RuntimeContext < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (quote ! (& context))) } } pub use crate :: HfCompiled ; # [cfg (stageleft_macro)] impl < 'a , ID > HfCompiled < 'a , ID > { pub fn hydroflow_ir (& self) -> & BTreeMap < usize , HydroflowGraph > { & self . hydroflow_ir } } # [cfg (stageleft_macro)] impl < 'a > HfCompiled < 'a , usize > { pub fn with_dynamic_id (self , id : impl Quoted < 'a , usize >) -> HfBuiltWithId < 'a > { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; let mut conditioned_tokens = None ; for (subgraph_id , flat_graph) in self . hydroflow_ir { let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; let my_extra_stmts = self . extra_stmts . get (& subgraph_id) . cloned () . unwrap_or_default () ; if let Some (conditioned_tokens) = conditioned_tokens . as_mut () { * conditioned_tokens = syn :: parse_quote ! { # conditioned_tokens else if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } } ; } else { conditioned_tokens = Some (syn :: parse_quote ! { if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } }) ; } } let conditioned_tokens : TokenStream = conditioned_tokens . unwrap () ; let id = id . splice () ; HfBuiltWithId { tokens : syn :: parse_quote ! ({ let __given_id = # id ; # conditioned_tokens else { panic ! ("Invalid node id: {}" , __given_id) ; } }) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfCompiled < 'a , () > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfCompiled < 'a , () > { fn to_tokens (mut self) -> (Option < TokenStream > , Option < TokenStream >) { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; if self . hydroflow_ir . len () != 1 { panic ! ("Expected exactly one subgraph in the Hydroflow IR") ; } let flat_graph = self . hydroflow_ir . remove (& 0) . unwrap () ; let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; (None , Some (tokens)) } } pub use crate :: HfBuiltWithId ; # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfBuiltWithId < 'a > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfBuiltWithId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (self . tokens)) } }
[INFO] [stdout]   |
[INFO] [stdout] help: ...otherwise replace it with an invocation of macro `deref`
[INFO] [stdout]   |
[INFO] [stdout] 1 - pub use std :: collections :: BTreeMap ; pub use std :: marker :: PhantomData ; pub use hydroflow :: scheduled :: context :: Context ; pub use hydroflow :: scheduled :: graph :: Hydroflow ; pub use hydroflow :: * ; pub use lang :: graph :: { partition_graph , HydroflowGraph } ; pub use proc_macro2 :: TokenStream ; pub use quote :: quote ; pub use stageleft :: runtime_support :: FreeVariable ; pub use stageleft :: Quoted ; pub mod runtime_support { pub use bincode ; } pub mod stream { pub use std :: cell :: RefCell ; pub use std :: hash :: Hash ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow :: bytes :: Bytes ; pub use hydroflow :: futures :: Sink ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: quote ; pub use serde :: de :: DeserializeOwned ; pub use serde :: Serialize ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use syn :: parse_quote ; pub use crate :: builder :: { ClusterIds , FlowLeaves } ; pub use crate :: cycle :: { CycleCollection , CycleComplete } ; pub use crate :: ir :: { DebugInstantiate , HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { CanSend , Location , LocationId } ; pub use crate :: { Cluster , Optional , Singleton } ; pub use crate :: stream :: Unbounded ; pub use crate :: stream :: Bounded ; pub use crate :: stream :: NoTick ; pub use crate :: stream :: Tick ; pub use crate :: stream :: Stream ; # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Stream { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Stream < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Stream { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , C , N > > ,) -> Stream < 'a , (T , O) , W , C , N > where O : Clone , { let other : Optional < 'a , O , Bounded , C , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn cross_product < O > (self , other : Stream < 'a , O , W , C , N >) -> Stream < 'a , (T , O) , W , C , N > where T : Clone , O : Clone , { if self . location_kind != other . location_kind { panic ! ("cross_product must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossProduct (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn union (self , other : Stream < 'a , T , W , C , N >) -> Stream < 'a , T , W , C , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn dest_sink < S : Unpin + Sink < T > + 'a > (self , sink : impl Quoted < 'a , S >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: DestSink { sink : sink . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn first (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } # [doc = " Allow this stream through if the other stream has elements, otherwise the output is empty."] pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } # [doc = " Allow this stream through if the other stream is empty, otherwise the output is empty."] pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn enumerate (self) -> Stream < 'a , (usize , T) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Enumerate (Box :: new (self . ir_node . into_inner ())) ,) } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn sort (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Ord , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Sort (Box :: new (self . ir_node . into_inner ())) ,) } pub fn count (self) -> Singleton < 'a , usize , Bounded , Tick , N > { self . fold (q ! (|| 0usize) , q ! (| count , _ | * count += 1)) } pub fn delta (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } pub fn unique (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Eq + Hash , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unique (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn tick_batch (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_prefix (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { self . tick_batch () . persist () } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn for_each < F : Fn (T) + 'a > (self , f : impl IntoQuotedMut < 'a , F >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: ForEach { input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , f : f . splice () . into () , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Unbounded , NoTick , N > { pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . tick_batch () . continue_if (samples . first ()) . all_ticks () } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Unbounded , NoTick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , C , N : Location > Stream < 'a , T , Bounded , C , N > { pub fn filter_not_in (self , other : Stream < 'a , T , Bounded , C , N >) -> Stream < 'a , T , Bounded , C , N > where T : Eq + Hash , { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Difference (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Stream < 'a , & T , W , C , N > { pub fn cloned (self) -> Stream < 'a , T , W , C , N > { self . map (q ! (| d | d . clone ())) } } # [cfg (stageleft_macro)] impl < 'a , K , V1 , W , C , N : Location > Stream < 'a , (K , V1) , W , C , N > { pub fn join < W2 , V2 > (self , n : Stream < 'a , (K , V2) , W2 , C , N > ,) -> Stream < 'a , (K , (V1 , V2)) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Join (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } pub fn anti_join < W2 > (self , n : Stream < 'a , K , W2 , C , N >) -> Stream < 'a , (K , V1) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("anti_join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: AntiJoin (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , K : Eq + Hash , V , N : Location > Stream < 'a , (K , V) , Bounded , Tick , N > { pub fn fold_keyed < A , I : Fn () -> A + 'a , F : Fn (& mut A , V) + 'a > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , A) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FoldKeyed { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce_keyed < F : Fn (& mut V , V) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , V) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: ReduceKeyed { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } pub fn get_this_crate () -> TokenStream { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , Span :: call_site ()) ; quote ! { # ident } } } } pub fn serialize_bincode < T : Serialize > (is_demux : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if is_demux { parse_quote ! { map (| (id , data) | { (id , # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into ()) }) } } else { parse_quote ! { map (| data | { # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into () }) } } } pub fn deserialize_bincode < T : DeserializeOwned > (tagged : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if tagged { parse_quote ! { map (| res | { let (id , b) = res . unwrap () ; (id , # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& b) . unwrap ()) }) } } else { parse_quote ! { map (| res | { # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& res . unwrap ()) . unwrap () }) } } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn send_bincode < N2 : Location , CoreType > (self , other : & N2 ,) -> Stream < 'a , N :: Out < CoreType > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T > , CoreType : Serialize + DeserializeOwned , { let serialize_pipeline = Some (serialize_bincode :: < CoreType > (N :: is_demux ())) ; let deserialize_pipeline = Some (deserialize_bincode :: < CoreType > (N :: is_tagged ())) ; Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bytes < N2 : Location > (self , other : & N2 ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T > , { Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline : None , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline : if N :: is_tagged () { Some (parse_quote ! (map (| (id , b) | (id , b . unwrap () . freeze ())))) } else { Some (parse_quote ! (map (| b | b . unwrap () . freeze ()))) } , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bincode_interleaved < N2 : Location , Tag , CoreType > (self , other : & N2 ,) -> Stream < 'a , CoreType , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T , Out < CoreType > = (Tag , CoreType) > , CoreType : Serialize + DeserializeOwned , { self . send_bincode :: < N2 , CoreType > (other) . map (q ! (| (_ , b) | b)) } pub fn send_bytes_interleaved < N2 : Location , Tag > (self , other : & N2 ,) -> Stream < 'a , Bytes , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T , Out < Bytes > = (Tag , Bytes) > , { self . send_bytes :: < N2 > (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bincode < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < T > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) > , T : Clone + Serialize + DeserializeOwned , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bincode (other) } pub fn broadcast_bincode_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , T , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) , Out < T > = (Tag , T) > + 'a , T : Clone + Serialize + DeserializeOwned , { self . broadcast_bincode (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bytes < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) > + 'a , T : Clone , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bytes (other) } pub fn broadcast_bytes_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , Bytes , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) , Out < Bytes > = (Tag , Bytes) > + 'a , T : Clone , { self . broadcast_bytes (other) . map (q ! (| (_ , b) | b)) } } } pub use stream :: { Bounded , NoTick , Stream , Tick , Unbounded } ; pub mod singleton { pub use std :: cell :: RefCell ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use crate :: builder :: FlowLeaves ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial , CycleComplete } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: Stream ; pub use crate :: singleton :: CrossResult ; # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Singleton < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Singleton :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } pub use crate :: singleton :: Singleton ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Singleton { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleComplete < 'a > for Singleton < 'a , T , Bounded , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleCollectionWithInitial < 'a > for Singleton < 'a , T , Bounded , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , initial : Self , l : LocationId ,) -> Self { Singleton :: new (l , ir_leaves , HfPlusNode :: Union (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , }) , initial . ir_node . into_inner () . into () ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Singleton < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Singleton { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , U , W , C , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (Self :: other_ir_node (other)) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Singleton < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CrossSingleton (Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , Box :: new (HfPlusNode :: Unpersist (Box :: new (Self :: other_ir_node (other)))) ,))) ,) } } pub use crate :: singleton :: Optional ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Optional { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } pub fn some (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: new (singleton . location_kind , singleton . ir_leaves , singleton . ir_node . into_inner () ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > From < Singleton < 'a , T , W , C , N > > for Optional < 'a , T , W , C , N > { fn from (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: some (singleton) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Optional < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Optional { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn into_stream (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , Tick , N > > ,) -> Optional < 'a , (T , O) , Bounded , Tick , N > where O : Clone , { let other : Optional < 'a , O , Bounded , Tick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn union (self , other : Optional < 'a , T , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Optional < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_samples (self) -> Stream < 'a , T , Unbounded , NoTick , N > { self . latest_tick () . all_ticks () } pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . latest_tick () . continue_if (samples . first ()) . latest () . tick_samples () } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Unbounded , NoTick , N > > ,) -> Optional < 'a , (T , O) , Unbounded , NoTick , N > where O : Clone , { let other : Optional < 'a , O , Unbounded , NoTick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } self . latest_tick () . cross_singleton (other . latest_tick ()) . latest () } } } pub use singleton :: { Optional , Singleton } ; pub mod location { pub use std :: marker :: PhantomData ; pub use crate :: location :: LocationId ; pub use crate :: location :: Location ; pub use crate :: location :: Process ; # [cfg (stageleft_macro)] impl < P > Clone for Process < P > { fn clone (& self) -> Self { Process { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < P > Location for Process < P > { fn id (& self) -> LocationId { LocationId :: Process (self . id) } } pub use crate :: location :: Cluster ; # [cfg (stageleft_macro)] impl < C > Clone for Cluster < C > { fn clone (& self) -> Self { Cluster { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < C > Location for Cluster < C > { fn id (& self) -> LocationId { LocationId :: Cluster (self . id) } } pub use crate :: location :: CanSend ; # [cfg (stageleft_macro)] impl < P1 , P2 > CanSend < Process < P2 > > for Process < P1 > { type In < T > = T ; type Out < T > = T ; fn is_demux () -> bool { false } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < P1 , C2 > CanSend < Cluster < C2 > > for Process < P1 > { type In < T > = (u32 , T) ; type Out < T > = T ; fn is_demux () -> bool { true } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < C1 , P2 > CanSend < Process < P2 > > for Cluster < C1 > { type In < T > = T ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { false } fn is_tagged () -> bool { true } } # [cfg (stageleft_macro)] impl < C1 , C2 > CanSend < Cluster < C2 > > for Cluster < C1 > { type In < T > = (u32 , T) ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { true } fn is_tagged () -> bool { true } } } pub use location :: { Cluster , Process } ; pub mod deploy { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use stageleft :: Quoted ; pub mod graphs { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use super :: { LocalDeploy , Node , ProcessSpec } ; pub use crate :: deploy :: graphs :: SingleProcessGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for SingleProcessGraph { type Process = SingleNode ; type Cluster = SingleNode ; type Meta = () ; type GraphId = () ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { SingleNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { SingleNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , SingleProcessGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> SingleNode { SingleNode { } } } pub use crate :: deploy :: graphs :: SingleNode ; # [cfg (stageleft_macro)] impl Node for SingleNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } pub use crate :: deploy :: graphs :: MultiGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for MultiGraph { type Process = MultiNode ; type Cluster = MultiNode ; type Meta = () ; type GraphId = usize ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { MultiNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { MultiNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , MultiGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> MultiNode { MultiNode { } } } pub use crate :: deploy :: graphs :: MultiNode ; # [cfg (stageleft_macro)] impl Node for MultiNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } } pub use graphs :: * ; pub use crate :: deploy :: LocalDeploy ; pub use crate :: deploy :: Deploy ; # [cfg (stageleft_macro)] impl < 'a , T : Deploy < 'a , Process = N , Cluster = C , Meta = M , GraphId = R > , N : Node < Meta = M > , C : Node < Meta = M > , M : Default , R , > LocalDeploy < 'a > for T { type Process = N ; type Cluster = C ; type Meta = M ; type GraphId = R ; fn has_trivial_node () -> bool { < T as Deploy < 'a > > :: has_trivial_node () } fn trivial_process (id : usize) -> Self :: Process { < T as Deploy < 'a > > :: trivial_process (id) } fn trivial_cluster (id : usize) -> Self :: Cluster { < T as Deploy < 'a > > :: trivail_cluster (id) } } pub use crate :: deploy :: ProcessSpec ; pub use crate :: deploy :: ClusterSpec ; pub use crate :: deploy :: Node ; } pub use deploy :: { ClusterSpec , Deploy , ProcessSpec } ; pub mod cycle { pub use std :: marker :: PhantomData ; pub use crate :: builder :: FlowLeaves ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: cycle :: CycleComplete ; pub use crate :: cycle :: CycleCollection ; pub use crate :: cycle :: CycleCollectionWithInitial ; pub use crate :: cycle :: HfCycle ; # [cfg (stageleft_macro)] impl < 'a , S : CycleComplete < 'a > > HfCycle < 'a , S > { pub fn complete (self , stream : S) { let ident = self . ident ; S :: complete (stream , ident) } } } pub use cycle :: HfCycle ; pub mod builder { pub use std :: cell :: RefCell ; pub use std :: collections :: HashMap ; pub use std :: marker :: PhantomData ; pub use std :: rc :: Rc ; pub use std :: time :: Duration ; pub use hydroflow :: futures :: stream :: Stream as FuturesStream ; pub use hydroflow :: { tokio , tokio_stream } ; pub use internal :: TokenStream ; pub use proc_macro2 :: Span ; pub use quote :: quote ; pub use runtime_support :: FreeVariable ; pub use stageleft :: * ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Cluster , Location , LocationId , Process } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: { HfCycle , Optional , RuntimeContext , Singleton , Stream } ; pub mod built { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use hydroflow_lang :: graph :: { eliminate_extra_unions_tees , HydroflowGraph } ; pub use super :: deploy :: { DeployFlow , DeployResult } ; pub use crate :: deploy :: { ClusterSpec , Deploy , LocalDeploy , ProcessSpec } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Cluster , Process } ; pub use crate :: HfCompiled ; pub use crate :: builder :: built :: BuiltFlow ; # [cfg (stageleft_macro)] impl < 'a > Drop for BuiltFlow < 'a > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped BuiltFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn ir (& self) -> & Vec < HfPlusLeaf < 'a > > { & self . ir } pub fn optimize_with (mut self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> BuiltFlow < 'a > { self . used = true ; BuiltFlow { ir : f (std :: mem :: take (& mut self . ir)) , processes : std :: mem :: take (& mut self . processes) , clusters : std :: mem :: take (& mut self . clusters) , used : false , _phantom : PhantomData , } } } pub fn build_inner (ir : & mut Vec < HfPlusLeaf >) -> BTreeMap < usize , HydroflowGraph > { let mut builders = BTreeMap :: new () ; let mut built_tees = HashMap :: new () ; let mut next_stmt_id = 0 ; for leaf in ir { leaf . emit (& mut builders , & mut built_tees , & mut next_stmt_id) ; } builders . into_iter () . map (| (k , v) | { let (mut flat_graph , _ , _) = v . build () ; eliminate_extra_unions_tees (& mut flat_graph) ; (k , flat_graph) }) . collect () } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn compile_no_network < D : LocalDeploy < 'a > > (mut self) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; HfCompiled { hydroflow_ir : build_inner (& mut self . ir) , extra_stmts : BTreeMap :: new () , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> BuiltFlow < 'a > { self . optimize_with (crate :: persist_pullup :: persist_pullup) } fn into_deploy < D : LocalDeploy < 'a > > (mut self) -> DeployFlow < 'a , D > { self . used = true ; let processes = if D :: has_trivial_node () { self . processes . iter () . map (| id | (* id , D :: trivial_process (* id))) . collect () } else { HashMap :: new () } ; let clusters = if D :: has_trivial_node () { self . clusters . iter () . map (| id | (* id , D :: trivial_cluster (* id))) . collect () } else { HashMap :: new () } ; DeployFlow { ir : std :: mem :: take (& mut self . ir) , nodes : processes , clusters , used : false , _phantom : PhantomData , } } pub fn with_process < P , D : LocalDeploy < 'a > > (self , process : & Process < P > , spec : impl ProcessSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_process (process , spec) } pub fn with_cluster < C , D : LocalDeploy < 'a > > (self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_cluster (cluster , spec) } pub fn compile < D : Deploy < 'a > + 'a > (self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . into_deploy :: < D > () . compile (env) } pub fn deploy < D : Deploy < 'a , CompileEnv = () > + 'a > (self , env : & mut D :: InstantiateEnv ,) -> DeployResult < 'a , D > { self . into_deploy :: < D > () . deploy (env) } } } pub mod deploy { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use proc_macro2 :: Span ; pub use stageleft :: Quoted ; pub use super :: built :: build_inner ; pub use crate :: deploy :: { LocalDeploy , Node } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: { Cluster , ClusterSpec , Deploy , HfCompiled , Process , ProcessSpec } ; pub use crate :: builder :: deploy :: DeployFlow ; # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > Drop for DeployFlow < 'a , D > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped DeployFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > DeployFlow < 'a , D > { pub fn with_process < P > (mut self , process : & Process < P > , spec : impl ProcessSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < P > () . to_string () ; self . nodes . insert (process . id , spec . build (process . id , & tag_name)) ; self } pub fn with_cluster < C > (mut self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < C > () . to_string () ; self . clusters . insert (cluster . id , spec . build (cluster . id , & tag_name)) ; self } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployFlow < 'a , D > { pub fn compile (mut self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; let mut seen_tees : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | leaf . compile_network :: < D > (env , & mut seen_tees , & self . nodes , & self . clusters)) . collect () ; let extra_stmts = self . extra_stmts (env) ; HfCompiled { hydroflow_ir : build_inner (& mut ir_leaves_networked) , extra_stmts , _phantom : PhantomData , } } fn extra_stmts (& self , env : & < D as Deploy < 'a > > :: CompileEnv) -> BTreeMap < usize , Vec < syn :: Stmt > > { let all_locations_count = self . nodes . len () + self . clusters . len () ; let mut extra_stmts : BTreeMap < usize , Vec < syn :: Stmt > > = BTreeMap :: new () ; for & c_id in self . clusters . keys () { let self_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , c_id) , Span :: call_site () ,) ; let self_id_expr = D :: cluster_self_id (env) . splice () ; extra_stmts . entry (c_id) . or_default () . push (syn :: parse_quote ! { let # self_id_ident = # self_id_expr ; }) ; for other_location in 0 .. all_locations_count { let other_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , c_id) , Span :: call_site () ,) ; let other_id_expr = D :: cluster_ids (env , c_id) . splice () ; extra_stmts . entry (other_location) . or_default () . push (syn :: parse_quote ! { let # other_id_ident = # other_id_expr ; }) ; } } extra_stmts } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a , CompileEnv = () > > DeployFlow < 'a , D > { # [must_use] pub fn deploy (mut self , env : & mut D :: InstantiateEnv) -> DeployResult < 'a , D > { self . used = true ; let mut seen_tees_instantiate : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | { leaf . compile_network :: < D > (& () , & mut seen_tees_instantiate , & self . nodes , & self . clusters ,) }) . collect () ; let mut compiled = build_inner (& mut ir_leaves_networked) ; let mut extra_stmts = self . extra_stmts (& ()) ; let mut meta = D :: Meta :: default () ; let (mut processes , mut clusters) = (std :: mem :: take (& mut self . nodes) . into_iter () . map (| (node_id , node) | { node . instantiate (env , & mut meta , compiled . remove (& node_id) . unwrap () , extra_stmts . remove (& node_id) . unwrap_or_default () ,) ; (node_id , node) }) . collect :: < HashMap < _ , _ > > () , std :: mem :: take (& mut self . clusters) . into_iter () . map (| (cluster_id , cluster) | { cluster . instantiate (env , & mut meta , compiled . remove (& cluster_id) . unwrap () , extra_stmts . remove (& cluster_id) . unwrap_or_default () ,) ; (cluster_id , cluster) }) . collect :: < HashMap < _ , _ > > () ,) ; for node in processes . values_mut () { node . update_meta (& meta) ; } for cluster in clusters . values_mut () { cluster . update_meta (& meta) ; } let mut seen_tees_connect = HashMap :: new () ; for leaf in ir_leaves_networked { leaf . connect_network (& mut seen_tees_connect) ; } DeployResult { processes , clusters , } } } pub use crate :: builder :: deploy :: DeployResult ; # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployResult < 'a , D > { pub fn get_process < P > (& self , p : & Process < P >) -> & D :: Process { let id = match p . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . processes . get (& id) . unwrap () } pub fn get_cluster < C > (& self , c : & Cluster < C >) -> & D :: Cluster { let id = match c . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . clusters . get (& id) . unwrap () } } } # [doc = " Tracks the leaves of the dataflow IR. This is referenced by"] # [doc = " `Stream` and `HfCycle` to build the IR. The inner option will"] # [doc = " be set to `None` when this builder is finalized."] pub type FlowLeaves < 'a > = Rc < RefCell < Option < Vec < HfPlusLeaf < 'a > > > > > ; pub use crate :: builder :: ClusterIds ; # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Vec < u32 > > for ClusterIds < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , & 'a Vec < u32 > > for ClusterIds < 'a > { } # [derive (Copy , Clone)] pub struct ClusterSelfId < 'a > { pub id : usize , pub _phantom : PhantomData < & 'a mut & 'a u32 > , } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < u32 > for ClusterSelfId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , u32 > for ClusterSelfId < 'a > { } pub use crate :: builder :: FlowBuilder ; # [cfg (stageleft_macro)] impl < 'a > Drop for FlowBuilder < 'a > { fn drop (& mut self) { if ! self . finalized { panic ! ("Dropped FlowBuilder without finalizing, you may have forgotten to call `with_default_optimize`, `optimize_with`, or `finalize`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > QuotedContext for FlowBuilder < 'a > { fn create () -> Self { FlowBuilder :: new () } } # [cfg (stageleft_macro)] impl < 'a > FlowBuilder < 'a > { # [allow (clippy :: new_without_default)] pub fn new () -> FlowBuilder < 'a > { FlowBuilder { ir_leaves : Rc :: new (RefCell :: new (Some (Vec :: new ()))) , nodes : RefCell :: new (vec ! []) , clusters : RefCell :: new (vec ! []) , cycle_ids : RefCell :: new (HashMap :: new ()) , next_node_id : RefCell :: new (0) , finalized : false , _phantom : PhantomData , } } pub fn finalize (mut self) -> built :: BuiltFlow < 'a > { self . finalized = true ; built :: BuiltFlow { ir : self . ir_leaves . borrow_mut () . take () . unwrap () , processes : self . nodes . replace (vec ! []) , clusters : self . clusters . replace (vec ! []) , used : false , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> built :: BuiltFlow < 'a > { self . finalize () . with_default_optimize () } pub fn optimize_with (self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> built :: BuiltFlow < 'a > { self . finalize () . optimize_with (f) } pub fn ir_leaves (& self) -> & FlowLeaves < 'a > { & self . ir_leaves } pub fn process < P > (& self) -> Process < P > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . nodes . borrow_mut () . push (id) ; Process { id , _phantom : PhantomData , } } pub fn cluster < C > (& self) -> Cluster < C > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . clusters . borrow_mut () . push (id) ; Cluster { id , _phantom : PhantomData , } } pub fn runtime_context (& self) -> RuntimeContext < 'a > { RuntimeContext { _phantom : PhantomData , } } pub fn cluster_members < C > (& self , cluster : & Cluster < C > ,) -> impl Quoted < 'a , & 'a Vec < u32 > > + Copy + 'a { ClusterIds { id : cluster . id , _phantom : PhantomData , } } pub fn cluster_self_id < C > (& self , cluster : & Cluster < C >) -> impl Quoted < 'a , u32 > + Copy + 'a { ClusterSelfId { id : cluster . id , _phantom : PhantomData , } } pub fn spin < L : Location > (& self , on : & L) -> Stream < 'a , () , Unbounded , NoTick , L > { Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Spin () , location_kind : on . id () , })) ,) } pub fn spin_batch < L : Location > (& self , on : & L , batch_size : impl Quoted < 'a , usize > + Copy + 'a ,) -> Stream < 'a , () , Bounded , Tick , L > { self . spin (on) . flat_map (q ! (move | _ | 0 .. batch_size)) . map (q ! (| _ | ())) . tick_batch () } pub fn source_stream < T , E : FuturesStream < Item = T > + Unpin , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Unbounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Stream (e . into ()) , location_kind : on . id () , })) ,) } pub fn source_iter < T , E : IntoIterator < Item = T > , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Bounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , })) ,) } pub fn singleton < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Singleton < 'a , T , Bounded , NoTick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Singleton :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,)))) ,) } pub fn singleton_first_tick < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Optional < 'a , T , Bounded , Tick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,) } pub fn source_interval < L : Location > (& self , on : & L , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , () , Unbounded , NoTick , L > { let interval = interval . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : on . id () , })) ,) } pub fn source_interval_delayed < L : Location > (& self , on : & L , delay : impl Quoted < 'a , Duration > + Copy + 'a , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , tokio :: time :: Instant , Unbounded , NoTick , L > { self . source_stream (on , q ! (tokio_stream :: wrappers :: IntervalStream :: new (tokio :: time :: interval_at (tokio :: time :: Instant :: now () + delay , interval))) ,) . tick_batch () . first () . latest () } pub fn cycle < S : CycleCollection < 'a > > (& self , on : & S :: Location) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , on . id ()) ,) } pub fn cycle_with_initial < S : CycleCollectionWithInitial < 'a > > (& self , on : & S :: Location , initial : S ,) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , initial , on . id ()) ,) } } } pub use builder :: FlowBuilder ; pub mod ir { pub use core :: panic ; pub use std :: cell :: RefCell ; pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow_lang :: graph :: FlatGraphBuilder ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: ToTokens ; pub use syn :: parse_quote ; pub use crate :: deploy :: Deploy ; pub use crate :: location :: LocationId ; pub use crate :: ir :: DebugExpr ; # [cfg (stageleft_macro)] impl From < syn :: Expr > for DebugExpr { fn from (expr : syn :: Expr) -> DebugExpr { DebugExpr (expr) } } # [cfg (stageleft_macro)] impl Deref for DebugExpr { type Target = syn :: Expr ; fn deref (& self) -> & Self :: Target { & self . 0 } } # [cfg (stageleft_macro)] impl ToTokens for DebugExpr { fn to_tokens (& self , tokens : & mut TokenStream) { self . 0 . to_tokens (tokens) ; } } # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugExpr { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "{}" , self . 0 . to_token_stream ()) } } pub use crate :: ir :: DebugInstantiate ; # [cfg (stageleft_macro)] impl < 'a > std :: fmt :: Debug for DebugInstantiate < 'a > { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<network instantiate>") } } pub use crate :: ir :: DebugPipelineFn ; # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugPipelineFn { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<function>") } } pub use crate :: ir :: HfPlusSource ; pub use crate :: ir :: HfPlusLeaf ; # [cfg (stageleft_macro)] impl < 'a > HfPlusLeaf < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . compile_network :: < D > (compile_env , s , nodes , clusters) ; } , seen_tees ,) } pub fn connect_network (self , seen_tees : & mut SeenTees < 'a >) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . connect_network (s) ; } , seen_tees ,) } pub fn transform_children (self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) -> HfPlusLeaf < 'a > { match self { HfPlusLeaf :: ForEach { f , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: ForEach { f , input } } HfPlusLeaf :: DestSink { sink , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: DestSink { sink , input } } HfPlusLeaf :: CycleSink { ident , location_kind , mut input , } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: CycleSink { ident , location_kind , input , } } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) { match self { HfPlusLeaf :: ForEach { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> for_each (# f) ; }) ; } HfPlusLeaf :: DestSink { sink , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink) ; }) ; } HfPlusLeaf :: CycleSink { ident , location_kind , input , } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; assert_eq ! (input_location_id , * location_id , "cycle_sink location mismatch") ; graph_builders . entry (* location_id) . or_default () . add_statement (parse_quote ! { # ident = # input_ident ; }) ; } } } } pub use crate :: ir :: HfPlusNode ; pub type SeenTees < 'a > = HashMap < * const RefCell < HfPlusNode < 'a > > , Rc < RefCell < HfPlusNode < 'a > > > > ; # [cfg (stageleft_macro)] impl < 'a > HfPlusNode < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (& mut self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) { self . transform_children (| n , s | n . compile_network :: < D > (compile_env , s , nodes , clusters) , seen_tees ,) ; if let HfPlusNode :: Network { from_location , to_location , instantiate_fn , .. } = self { let (sink_expr , source_expr , connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { let ((sink , source) , connect_fn) = match (from_location , to_location) { (LocationId :: Process (from) , LocationId :: Process (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: o2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Process (from) , LocationId :: Cluster (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: o2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Process (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: m2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Cluster (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: m2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } } ; (sink , source , connect_fn) } DebugInstantiate :: Finalized (_ , _ , _) => panic ! ("network already finalized") , } ; * instantiate_fn = DebugInstantiate :: Finalized (sink_expr , source_expr , connect_fn) ; } } pub fn connect_network (& mut self , seen_tees : & mut SeenTees < 'a >) { self . transform_children (| n , s | n . connect_network (s) , seen_tees) ; if let HfPlusNode :: Network { instantiate_fn , .. } = self { match instantiate_fn { DebugInstantiate :: Building () => panic ! ("network not built") , DebugInstantiate :: Finalized (_ , _ , ref connect_fn) => { connect_fn () ; } } } } pub fn transform_children (& mut self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) { match self { HfPlusNode :: Placeholder => { panic ! () ; } HfPlusNode :: Source { .. } => { } HfPlusNode :: CycleSource { .. } => { } HfPlusNode :: Tee { inner } => { if let Some (transformed) = seen_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { * inner = transformed . clone () ; } else { let transformed_cell = Rc :: new (RefCell :: new (HfPlusNode :: Placeholder)) ; seen_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , transformed_cell . clone () ,) ; let mut orig = inner . replace (HfPlusNode :: Placeholder) ; transform (& mut orig , seen_tees) ; * transformed_cell . borrow_mut () = orig ; * inner = transformed_cell ; } } HfPlusNode :: Persist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Unpersist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Delta (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Union (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossProduct (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossSingleton (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Join (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Difference (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: AntiJoin (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Map { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FlatMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Filter { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FilterMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Sort (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: DeferTick (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Enumerate (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Inspect { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Unique (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Fold { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FoldKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Reduce { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: ReduceKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Network { input , .. } => { transform (input . as_mut () , seen_tees) ; } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) -> (syn :: Ident , usize) { match self { HfPlusNode :: Placeholder => { panic ! () } HfPlusNode :: Persist (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let persist_id = * next_stmt_id ; * next_stmt_id += 1 ; let persist_ident = syn :: Ident :: new (& format ! ("stream_{}" , persist_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # persist_ident = # inner_ident -> persist ::<'static > () ; }) ; (persist_ident , location) } HfPlusNode :: Unpersist (_) => { panic ! ("Unpersist is a marker node and should have been optimized away. This is likely a compiler bug.") } HfPlusNode :: Delta (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let delta_id = * next_stmt_id ; * next_stmt_id += 1 ; let delta_ident = syn :: Ident :: new (& format ! ("stream_{}" , delta_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # delta_ident = # inner_ident -> multiset_delta () ; }) ; (delta_ident , location) } HfPlusNode :: Source { source , location_kind , } => { let source_id = * next_stmt_id ; * next_stmt_id += 1 ; let source_ident = syn :: Ident :: new (& format ! ("stream_{}" , source_id) , Span :: call_site ()) ; let source_stmt = match source { HfPlusSource :: Stream (expr) => { parse_quote ! { # source_ident = source_stream (# expr) ; } } HfPlusSource :: Iter (expr) => { parse_quote ! { # source_ident = source_iter (# expr) ; } } HfPlusSource :: Interval (expr) => { parse_quote ! { # source_ident = source_interval (# expr) ; } } HfPlusSource :: Spin () => { parse_quote ! { # source_ident = spin () ; } } } ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; graph_builders . entry (* location_id) . or_default () . add_statement (source_stmt) ; (source_ident , * location_id) } HfPlusNode :: CycleSource { ident , location_kind , } => { let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; (ident . clone () , * location_id) } HfPlusNode :: Tee { inner } => { if let Some (ret) = built_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { ret . clone () } else { let (inner_ident , inner_location_id) = inner . borrow () . emit (graph_builders , built_tees , next_stmt_id) ; let tee_id = * next_stmt_id ; * next_stmt_id += 1 ; let tee_ident = syn :: Ident :: new (& format ! ("stream_{}" , tee_id) , Span :: call_site ()) ; let builder = graph_builders . entry (inner_location_id) . or_default () ; builder . add_statement (parse_quote ! { # tee_ident = # inner_ident -> tee () ; }) ; built_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , (tee_ident . clone () , inner_location_id) ,) ; (tee_ident , inner_location_id) } } HfPlusNode :: Union (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "union inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let union_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # union_ident = union () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [0] # union_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # union_ident ; }) ; (union_ident , left_location_id) } HfPlusNode :: CrossSingleton (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "cross_singleton inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let cross_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # cross_ident = cross_singleton () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [input] # cross_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [single] # cross_ident ; }) ; (cross_ident , left_location_id) } HfPlusNode :: CrossProduct (..) | HfPlusNode :: Join (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: CrossProduct (..)) { parse_quote ! (cross_join_multiset) } else { parse_quote ! (join_multiset) } ; let (HfPlusNode :: CrossProduct (left , right) | HfPlusNode :: Join (left , right)) = self else { unreachable ! () } ; let (left_inner , left_was_persist) = if let HfPlusNode :: Persist (left) = left . as_ref () { (left , true) } else { (left , false) } ; let (right_inner , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left_inner . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right_inner . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "join / cross product inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; match (left_was_persist , right_was_persist) { (true , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'static > () ; }) ; } (true , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'tick > () ; }) ; } (false , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } (false , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } } ; builder . add_statement (parse_quote ! { # left_ident -> [0] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Difference (..) | HfPlusNode :: AntiJoin (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Difference (..)) { parse_quote ! (difference_multiset) } else { parse_quote ! (anti_join_multiset) } ; let (HfPlusNode :: Difference (left , right) | HfPlusNode :: AntiJoin (left , right)) = self else { unreachable ! () } ; let (right , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "difference / anti join inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; if right_was_persist { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } else { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } builder . add_statement (parse_quote ! { # left_ident -> [pos] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [neg] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Map { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let map_id = * next_stmt_id ; * next_stmt_id += 1 ; let map_ident = syn :: Ident :: new (& format ! ("stream_{}" , map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # map_ident = # input_ident -> map (# f) ; }) ; (map_ident , input_location_id) } HfPlusNode :: FlatMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let flat_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let flat_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , flat_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # flat_map_ident = # input_ident -> flat_map (# f) ; }) ; (flat_map_ident , input_location_id) } HfPlusNode :: Filter { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_ident = # input_ident -> filter (# f) ; }) ; (filter_ident , input_location_id) } HfPlusNode :: FilterMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_map_ident = # input_ident -> filter_map (# f) ; }) ; (filter_map_ident , input_location_id) } HfPlusNode :: Sort (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sort_id = * next_stmt_id ; * next_stmt_id += 1 ; let sort_ident = syn :: Ident :: new (& format ! ("stream_{}" , sort_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # sort_ident = # input_ident -> sort () ; }) ; (sort_ident , input_location_id) } HfPlusNode :: DeferTick (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let defer_tick_id = * next_stmt_id ; * next_stmt_id += 1 ; let defer_tick_ident = syn :: Ident :: new (& format ! ("stream_{}" , defer_tick_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # defer_tick_ident = # input_ident -> defer_tick_lazy () ; }) ; (defer_tick_ident , input_location_id) } HfPlusNode :: Enumerate (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let enumerate_id = * next_stmt_id ; * next_stmt_id += 1 ; let enumerate_ident = syn :: Ident :: new (& format ! ("stream_{}" , enumerate_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # enumerate_ident = # input_ident -> enumerate () ; }) ; (enumerate_ident , input_location_id) } HfPlusNode :: Inspect { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let inspect_id = * next_stmt_id ; * next_stmt_id += 1 ; let inspect_ident = syn :: Ident :: new (& format ! ("stream_{}" , inspect_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # inspect_ident = # input_ident -> inspect (# f) ; }) ; (inspect_ident , input_location_id) } HfPlusNode :: Unique (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let unique_id = * next_stmt_id ; * next_stmt_id += 1 ; let unique_ident = syn :: Ident :: new (& format ! ("stream_{}" , unique_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # unique_ident = # input_ident -> unique ::<'tick > () ; }) ; (unique_ident , input_location_id) } HfPlusNode :: Fold { .. } | HfPlusNode :: FoldKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Fold { .. }) { parse_quote ! (fold) } else { parse_quote ! (fold_keyed) } ; let (HfPlusNode :: Fold { init , acc , input } | HfPlusNode :: FoldKeyed { init , acc , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let fold_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'static > (# init , # acc) ; }) ; } else { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'tick > (# init , # acc) ; }) ; } (fold_ident , input_location_id) } HfPlusNode :: Reduce { .. } | HfPlusNode :: ReduceKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Reduce { .. }) { parse_quote ! (reduce) } else { parse_quote ! (reduce_keyed) } ; let (HfPlusNode :: Reduce { f , input } | HfPlusNode :: ReduceKeyed { f , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let reduce_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'static > (# f) ; }) ; } else { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'tick > (# f) ; }) ; } (reduce_ident , input_location_id) } HfPlusNode :: Network { from_location : _ , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input , } => { let (sink_expr , source_expr , _connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { panic ! ("Expected the network to be finalized") } DebugInstantiate :: Finalized (sink , source , connect_fn) => { (sink , source , connect_fn) } } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sender_builder = graph_builders . entry (input_location_id) . or_default () ; if let Some (serialize_pipeline) = serialize_pipeline { sender_builder . add_statement (parse_quote ! { # input_ident -> # serialize_pipeline -> dest_sink (# sink_expr) ; }) ; } else { sender_builder . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink_expr) ; }) ; } let to_id = match to_location { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let receiver_builder = graph_builders . entry (* to_id) . or_default () ; let receiver_stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let receiver_stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , receiver_stream_id) , Span :: call_site ()) ; if let Some (deserialize_pipeline) = deserialize_pipeline { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) -> # deserialize_pipeline ; }) ; } else { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) ; }) ; } (receiver_stream_ident , * to_id) } } } } } pub mod persist_pullup { pub use std :: cell :: RefCell ; pub use std :: collections :: HashSet ; pub use std :: ops :: Deref ; pub use crate :: ir :: * ; pub fn persist_pullup_node < 'a > (node : & mut HfPlusNode < 'a > , seen_tees : & mut SeenTees < 'a > , persist_pulled_tees : & mut HashSet < * const RefCell < HfPlusNode < 'a > > > ,) { node . transform_children (| n , s | persist_pullup_node (n , s , persist_pulled_tees) , seen_tees ,) ; match node { HfPlusNode :: Unpersist (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Unpersist (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Delta (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Delta (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Tee { inner } => { if persist_pulled_tees . contains (& (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >)) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } else { let inner_borrow = inner . borrow () ; if let HfPlusNode :: Persist (_) = inner_borrow . deref () { drop (inner_borrow) ; persist_pulled_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >) ; if let HfPlusNode :: Persist (box behind_persist) = inner . replace (HfPlusNode :: Placeholder) { * inner . borrow_mut () = behind_persist ; } else { unreachable ! () } * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } } } HfPlusNode :: Map { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Map { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Map { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: FlatMap { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: FlatMap { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: FlatMap { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Filter { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Filter { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Filter { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Network { input : box HfPlusNode :: Persist (_) , .. } => { if let HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Union (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Union (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Union (left , right))) ; } else { unreachable ! () } } HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: CrossProduct (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,) ,)))) ; } else { unreachable ! () } } HfPlusNode :: Join (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Join (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: Join (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,))))) ; } else { unreachable ! () } } _ => { } } } pub fn persist_pullup (ir : Vec < HfPlusLeaf >) -> Vec < HfPlusLeaf > { let mut seen_tees = Default :: default () ; let mut persist_pulled_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| n , s | persist_pullup_node (n , s , & mut persist_pulled_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn persist_pullup_through_map () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } # [test] fn persist_pullup_behind_tee () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; let before_tee = flow . source_iter (& process , q ! (0 .. 10)) . tick_batch () . persist () ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } } } pub mod profiler { pub use std :: cell :: RefCell ; pub use hydroflow :: futures :: channel :: mpsc :: UnboundedSender ; pub use stageleft :: * ; pub use crate as hydroflow_plus ; pub use crate :: ir :: * ; pub use crate :: RuntimeContext ; pub fn increment_counter (count : & mut u64) { * count += 1 ; } pub fn quoted_any_fn < 'a , F : Fn (& usize) + 'a , Q : IntoQuotedMut < 'a , F > > (q : Q) -> Q { q } # [doc = " Add a profiling node before each node to count the cardinality of its input"] pub fn add_profiling_node < 'a > (node : & mut HfPlusNode < 'a > , _context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > , id : & mut u32 , seen_tees : & mut SeenTees < 'a > ,) { let my_id = * id ; * id += 1 ; node . transform_children (| node , seen_tees | { add_profiling_node (node , _context , counters , counter_queue , id , seen_tees) } , seen_tees ,) ; let orig_node = std :: mem :: replace (node , HfPlusNode :: Placeholder) ; * node = HfPlusNode :: Inspect { f : quoted_any_fn (q ! ({ counter_queue . borrow () . unbounded_send ((my_id as usize , counters . borrow () [my_id as usize])) . unwrap () ; counters . borrow_mut () [my_id as usize] = 0 ; move | _ | { hydroflow_plus :: profiler :: increment_counter (& mut counters . borrow_mut () [my_id as usize] ,) ; } })) . splice () . into () , input : Box :: new (orig_node) , } } # [doc = " Count the cardinality of each input and periodically output to a file"] pub fn profiling < 'a > (ir : Vec < HfPlusLeaf < 'a > > , context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > ,) -> Vec < HfPlusLeaf < 'a > > { let mut id = 0 ; let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | { add_profiling_node (node , context , counters , counter_queue , & mut id , seen_tees) } , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn profiler_wrapping_all_operators () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let runtime_context = flow . runtime_context () ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (& built . ir ()) ; let counters = RuntimeData :: new ("Fake") ; let counter_queue = RuntimeData :: new ("Fake") ; let pushed_down = built . with_default_optimize () . optimize_with (| ir | super :: profiling (ir , runtime_context , counters , counter_queue)) ; insta :: assert_debug_snapshot ! (& pushed_down . ir ()) ; let _ = pushed_down . compile_no_network :: < MultiGraph > () ; } } } pub mod properties { pub use std :: collections :: HashSet ; pub use stageleft :: * ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , SeenTees } ; pub use crate :: properties :: PropertyDatabase ; # [doc = " Allows us to convert the hydroflow datatype for folds to a binary operation for the algebra"] # [doc = " property tests."] # [allow (dead_code)] pub fn convert_hf_to_binary < I , A : Default , F : Fn (& mut A , I) > (f : F) -> impl Fn (I , I) -> A { move | a , b | { let mut acc = Default :: default () ; f (& mut acc , a) ; f (& mut acc , b) ; acc } } # [cfg (stageleft_macro)] impl PropertyDatabase { # [doc = " Tags the expression as commutative."] pub fn add_commutative_tag < 'a , I , A , F : Fn (& mut A , I) , Q : Quoted < 'a , F > + Clone > (& mut self , expr : Q ,) -> Q { let expr_clone = expr . clone () ; self . commutative . insert (expr_clone . splice ()) ; expr } pub fn is_tagged_commutative (& self , expr : & syn :: Expr) -> bool { self . commutative . contains (expr) } } pub fn properties_optimize_node < 'a > (node : & mut HfPlusNode < 'a > , db : & PropertyDatabase , seen_tees : & mut SeenTees < 'a > ,) { node . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , seen_tees ,) ; match node { HfPlusNode :: ReduceKeyed { f , .. } if db . is_tagged_commutative (& f . 0) => { dbg ! ("IDENTIFIED COMMUTATIVE OPTIMIZATION for {:?}" , & f) ; } _ => { } } } pub fn properties_optimize < 'a > (ir : Vec < HfPlusLeaf < 'a > > , db : & PropertyDatabase ,) -> Vec < HfPlusLeaf < 'a > > { let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use super :: * ; use crate :: deploy :: SingleProcessGraph ; use crate :: FlowBuilder ; # [test] fn test_property_database () { let mut db = PropertyDatabase :: default () ; assert ! (! db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; let _ = db . add_commutative_tag (q ! (| a : & mut i32 , b : i32 | * a += b)) ; assert ! (db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; } # [test] fn test_property_optimized () { let flow = FlowBuilder :: new () ; let mut database = PropertyDatabase :: default () ; let process = flow . process :: < () > () ; let counter_func = q ! (| count : & mut i32 , _ | * count += 1) ; let _ = database . add_commutative_tag (counter_func) ; flow . source_iter (& process , q ! (vec ! [])) . map (q ! (| string : String | (string , ()))) . tick_batch () . fold_keyed (q ! (|| 0) , counter_func) . all_ticks () . for_each (q ! (| (string , count) | println ! ("{}: {}" , string , count))) ; let built = flow . finalize () . optimize_with (| ir | properties_optimize (ir , & database)) . with_default_optimize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let _ = built . compile_no_network :: < SingleProcessGraph > () ; } } } pub use crate :: RuntimeContext ; # [cfg (stageleft_macro)] impl Copy for RuntimeContext < '_ > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Context > for RuntimeContext < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (quote ! (& context))) } } pub use crate :: HfCompiled ; # [cfg (stageleft_macro)] impl < 'a , ID > HfCompiled < 'a , ID > { pub fn hydroflow_ir (& self) -> & BTreeMap < usize , HydroflowGraph > { & self . hydroflow_ir } } # [cfg (stageleft_macro)] impl < 'a > HfCompiled < 'a , usize > { pub fn with_dynamic_id (self , id : impl Quoted < 'a , usize >) -> HfBuiltWithId < 'a > { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; let mut conditioned_tokens = None ; for (subgraph_id , flat_graph) in self . hydroflow_ir { let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; let my_extra_stmts = self . extra_stmts . get (& subgraph_id) . cloned () . unwrap_or_default () ; if let Some (conditioned_tokens) = conditioned_tokens . as_mut () { * conditioned_tokens = syn :: parse_quote ! { # conditioned_tokens else if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } } ; } else { conditioned_tokens = Some (syn :: parse_quote ! { if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } }) ; } } let conditioned_tokens : TokenStream = conditioned_tokens . unwrap () ; let id = id . splice () ; HfBuiltWithId { tokens : syn :: parse_quote ! ({ let __given_id = # id ; # conditioned_tokens else { panic ! ("Invalid node id: {}" , __given_id) ; } }) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfCompiled < 'a , () > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfCompiled < 'a , () > { fn to_tokens (mut self) -> (Option < TokenStream > , Option < TokenStream >) { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; if self . hydroflow_ir . len () != 1 { panic ! ("Expected exactly one subgraph in the Hydroflow IR") ; } let flat_graph = self . hydroflow_ir . remove (& 0) . unwrap () ; let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; (None , Some (tokens)) } } pub use crate :: HfBuiltWithId ; # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfBuiltWithId < 'a > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfBuiltWithId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (self . tokens)) } }
[INFO] [stdout] 1 + pub use std :: collections :: BTreeMap ; pub use std :: marker :: PhantomData ; pub use hydroflow :: scheduled :: context :: Context ; pub use hydroflow :: scheduled :: graph :: Hydroflow ; pub use hydroflow :: * ; pub use lang :: graph :: { partition_graph , HydroflowGraph } ; pub use proc_macro2 :: TokenStream ; pub use quote :: quote ; pub use stageleft :: runtime_support :: FreeVariable ; pub use stageleft :: Quoted ; pub mod runtime_support { pub use bincode ; } pub mod stream { pub use std :: cell :: RefCell ; pub use std :: hash :: Hash ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow :: bytes :: Bytes ; pub use hydroflow :: futures :: Sink ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: quote ; pub use serde :: de :: DeserializeOwned ; pub use serde :: Serialize ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use syn :: parse_quote ; pub use crate :: builder :: { ClusterIds , FlowLeaves } ; pub use crate :: cycle :: { CycleCollection , CycleComplete } ; pub use crate :: ir :: { DebugInstantiate , HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { CanSend , Location , LocationId } ; pub use crate :: { Cluster , Optional , Singleton } ; pub use crate :: stream :: Unbounded ; pub use crate :: stream :: Bounded ; pub use crate :: stream :: NoTick ; pub use crate :: stream :: Tick ; pub use crate :: stream :: Stream ; # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Stream { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Stream < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Stream { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , C , N > > ,) -> Stream < 'a , (T , O) , W , C , N > where O : Clone , { let other : Optional < 'a , O , Bounded , C , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn cross_product < O > (self , other : Stream < 'a , O , W , C , N >) -> Stream < 'a , (T , O) , W , C , N > where T : Clone , O : Clone , { if self . location_kind != other . location_kind { panic ! ("cross_product must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossProduct (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn union (self , other : Stream < 'a , T , W , C , N >) -> Stream < 'a , T , W , C , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn dest_sink < S : Unpin + Sink < T > + 'a > (self , sink : impl Quoted < 'a , S >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: DestSink { sink : sink . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn first (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } # [doc = " Allow this stream through if the other stream has elements, otherwise the output is empty."] pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } # [doc = " Allow this stream through if the other stream is empty, otherwise the output is empty."] pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn enumerate (self) -> Stream < 'a , (usize , T) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Enumerate (Box :: new (self . ir_node . into_inner ())) ,) } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn sort (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Ord , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Sort (Box :: new (self . ir_node . into_inner ())) ,) } pub fn count (self) -> Singleton < 'a , usize , Bounded , Tick , N > { self . fold (q ! (|| 0usize) , q ! (| count , _ | * count += 1)) } pub fn delta (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } pub fn unique (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Eq + Hash , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unique (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn tick_batch (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_prefix (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { self . tick_batch () . persist () } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn for_each < F : Fn (T) + 'a > (self , f : impl IntoQuotedMut < 'a , F >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: ForEach { input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , f : f . splice () . into () , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Unbounded , NoTick , N > { pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . tick_batch () . continue_if (samples . first ()) . all_ticks () } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Unbounded , NoTick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , C , N : Location > Stream < 'a , T , Bounded , C , N > { pub fn filter_not_in (self , other : Stream < 'a , T , Bounded , C , N >) -> Stream < 'a , T , Bounded , C , N > where T : Eq + Hash , { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Difference (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Stream < 'a , & T , W , C , N > { pub fn cloned (self) -> Stream < 'a , T , W , C , N > { self . map (q ! (| d | d . clone ())) } } # [cfg (stageleft_macro)] impl < 'a , K , V1 , W , C , N : Location > Stream < 'a , (K , V1) , W , C , N > { pub fn join < W2 , V2 > (self , n : Stream < 'a , (K , V2) , W2 , C , N > ,) -> Stream < 'a , (K , (V1 , V2)) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Join (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } pub fn anti_join < W2 > (self , n : Stream < 'a , K , W2 , C , N >) -> Stream < 'a , (K , V1) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("anti_join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: AntiJoin (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , K : Eq + Hash , V , N : Location > Stream < 'a , (K , V) , Bounded , Tick , N > { pub fn fold_keyed < A , I : Fn () -> A + 'a , F : Fn (& mut A , V) + 'a > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , A) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FoldKeyed { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce_keyed < F : Fn (& mut V , V) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , V) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: ReduceKeyed { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } pub fn get_this_crate () -> TokenStream { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , Span :: call_site ()) ; quote ! { # ident } } } } pub fn serialize_bincode < T : Serialize > (is_demux : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if is_demux { parse_quote ! { map (| (id , data) | { (id , # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into ()) }) } } else { parse_quote ! { map (| data | { # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into () }) } } } pub fn deserialize_bincode < T : DeserializeOwned > (tagged : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if tagged { parse_quote ! { map (| res | { let (id , b) = res . unwrap () ; (id , # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& b) . unwrap ()) }) } } else { parse_quote ! { map (| res | { # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& res . unwrap ()) . unwrap () }) } } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn send_bincode < N2 : Location , CoreType > (self , other : & N2 ,) -> Stream < 'a , N :: Out < CoreType > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T > , CoreType : Serialize + DeserializeOwned , { let serialize_pipeline = Some (serialize_bincode :: < CoreType > (N :: is_demux ())) ; let deserialize_pipeline = Some (deserialize_bincode :: < CoreType > (N :: is_tagged ())) ; Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bytes < N2 : Location > (self , other : & N2 ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T > , { Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline : None , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline : if N :: is_tagged () { Some (parse_quote ! (map (| (id , b) | (id , b . unwrap () . freeze ())))) } else { Some (parse_quote ! (map (| b | b . unwrap () . freeze ()))) } , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bincode_interleaved < N2 : Location , Tag , CoreType > (self , other : & N2 ,) -> Stream < 'a , CoreType , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T , Out < CoreType > = (Tag , CoreType) > , CoreType : Serialize + DeserializeOwned , { self . send_bincode :: < N2 , CoreType > (other) . map (q ! (| (_ , b) | b)) } pub fn send_bytes_interleaved < N2 : Location , Tag > (self , other : & N2 ,) -> Stream < 'a , Bytes , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T , Out < Bytes > = (Tag , Bytes) > , { self . send_bytes :: < N2 > (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bincode < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < T > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) > , T : Clone + Serialize + DeserializeOwned , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bincode (other) } pub fn broadcast_bincode_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , T , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) , Out < T > = (Tag , T) > + 'a , T : Clone + Serialize + DeserializeOwned , { self . broadcast_bincode (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bytes < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) > + 'a , T : Clone , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bytes (other) } pub fn broadcast_bytes_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , Bytes , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) , Out < Bytes > = (Tag , Bytes) > + 'a , T : Clone , { self . broadcast_bytes (other) . map (q ! (| (_ , b) | b)) } } } pub use stream :: { Bounded , NoTick , Stream , Tick , Unbounded } ; pub mod singleton { pub use std :: cell :: RefCell ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use crate :: builder :: FlowLeaves ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial , CycleComplete } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: Stream ; pub use crate :: singleton :: CrossResult ; # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Singleton < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Singleton :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } pub use crate :: singleton :: Singleton ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Singleton { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleComplete < 'a > for Singleton < 'a , T , Bounded , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleCollectionWithInitial < 'a > for Singleton < 'a , T , Bounded , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , initial : Self , l : LocationId ,) -> Self { Singleton :: new (l , ir_leaves , HfPlusNode :: Union (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , }) , initial . ir_node . into_inner () . into () ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Singleton < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Singleton { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , U , W , C , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (Self :: other_ir_node (other)) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Singleton < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CrossSingleton (Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , Box :: new (HfPlusNode :: Unpersist (Box :: new (Self :: other_ir_node (other)))) ,))) ,) } } pub use crate :: singleton :: Optional ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Optional { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } pub fn some (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: new (singleton . location_kind , singleton . ir_leaves , singleton . ir_node . into_inner () ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > From < Singleton < 'a , T , W , C , N > > for Optional < 'a , T , W , C , N > { fn from (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: some (singleton) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Optional < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Optional { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn into_stream (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , Tick , N > > ,) -> Optional < 'a , (T , O) , Bounded , Tick , N > where O : Clone , { let other : Optional < 'a , O , Bounded , Tick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn union (self , other : Optional < 'a , T , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Optional < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_samples (self) -> Stream < 'a , T , Unbounded , NoTick , N > { self . latest_tick () . all_ticks () } pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . latest_tick () . continue_if (samples . first ()) . latest () . tick_samples () } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Unbounded , NoTick , N > > ,) -> Optional < 'a , (T , O) , Unbounded , NoTick , N > where O : Clone , { let other : Optional < 'a , O , Unbounded , NoTick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } self . latest_tick () . cross_singleton (other . latest_tick ()) . latest () } } } pub use singleton :: { Optional , Singleton } ; pub mod location { pub use std :: marker :: PhantomData ; pub use crate :: location :: LocationId ; pub use crate :: location :: Location ; pub use crate :: location :: Process ; # [cfg (stageleft_macro)] impl < P > Clone for Process < P > { fn clone (& self) -> Self { Process { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < P > Location for Process < P > { fn id (& self) -> LocationId { LocationId :: Process (self . id) } } pub use crate :: location :: Cluster ; # [cfg (stageleft_macro)] impl < C > Clone for Cluster < C > { fn clone (& self) -> Self { Cluster { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < C > Location for Cluster < C > { fn id (& self) -> LocationId { LocationId :: Cluster (self . id) } } pub use crate :: location :: CanSend ; # [cfg (stageleft_macro)] impl < P1 , P2 > CanSend < Process < P2 > > for Process < P1 > { type In < T > = T ; type Out < T > = T ; fn is_demux () -> bool { false } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < P1 , C2 > CanSend < Cluster < C2 > > for Process < P1 > { type In < T > = (u32 , T) ; type Out < T > = T ; fn is_demux () -> bool { true } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < C1 , P2 > CanSend < Process < P2 > > for Cluster < C1 > { type In < T > = T ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { false } fn is_tagged () -> bool { true } } # [cfg (stageleft_macro)] impl < C1 , C2 > CanSend < Cluster < C2 > > for Cluster < C1 > { type In < T > = (u32 , T) ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { true } fn is_tagged () -> bool { true } } } pub use location :: { Cluster , Process } ; pub mod deploy { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use stageleft :: Quoted ; pub mod graphs { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use super :: { LocalDeploy , Node , ProcessSpec } ; pub use crate :: deploy :: graphs :: SingleProcessGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for SingleProcessGraph { type Process = SingleNode ; type Cluster = SingleNode ; type Meta = () ; type GraphId = () ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { SingleNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { SingleNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , SingleProcessGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> SingleNode { SingleNode { } } } pub use crate :: deploy :: graphs :: SingleNode ; # [cfg (stageleft_macro)] impl Node for SingleNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } pub use crate :: deploy :: graphs :: MultiGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for MultiGraph { type Process = MultiNode ; type Cluster = MultiNode ; type Meta = () ; type GraphId = usize ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { MultiNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { MultiNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , MultiGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> MultiNode { MultiNode { } } } pub use crate :: deploy :: graphs :: MultiNode ; # [cfg (stageleft_macro)] impl Node for MultiNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } } pub use graphs :: * ; pub use crate :: deploy :: LocalDeploy ; pub use crate :: deploy :: Deploy ; # [cfg (stageleft_macro)] impl < 'a , T : Deploy < 'a , Process = N , Cluster = C , Meta = M , GraphId = R > , N : Node < Meta = M > , C : Node < Meta = M > , M : Default , R , > LocalDeploy < 'a > for T { type Process = N ; type Cluster = C ; type Meta = M ; type GraphId = R ; fn has_trivial_node () -> bool { < T as Deploy < 'a > > :: has_trivial_node () } fn trivial_process (id : usize) -> Self :: Process { < T as Deploy < 'a > > :: trivial_process (id) } fn trivial_cluster (id : usize) -> Self :: Cluster { < T as Deploy < 'a > > :: trivail_cluster (id) } } pub use crate :: deploy :: ProcessSpec ; pub use crate :: deploy :: ClusterSpec ; pub use crate :: deploy :: Node ; } pub use deploy :: { ClusterSpec , Deploy , ProcessSpec } ; pub mod cycle { pub use std :: marker :: PhantomData ; pub use crate :: builder :: FlowLeaves ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: cycle :: CycleComplete ; pub use crate :: cycle :: CycleCollection ; pub use crate :: cycle :: CycleCollectionWithInitial ; pub use crate :: cycle :: HfCycle ; # [cfg (stageleft_macro)] impl < 'a , S : CycleComplete < 'a > > HfCycle < 'a , S > { pub fn complete (self , stream : S) { let ident = self . ident ; S :: complete (stream , ident) } } } pub use cycle :: HfCycle ; pub mod builder { pub use std :: cell :: RefCell ; pub use std :: collections :: HashMap ; pub use std :: marker :: PhantomData ; pub use std :: rc :: Rc ; pub use std :: time :: Duration ; pub use hydroflow :: futures :: stream :: Stream as FuturesStream ; pub use hydroflow :: { tokio , tokio_stream } ; pub use internal :: TokenStream ; pub use proc_macro2 :: Span ; pub use quote :: quote ; pub use runtime_support :: FreeVariable ; pub use stageleft :: * ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Cluster , Location , LocationId , Process } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: { HfCycle , Optional , RuntimeContext , Singleton , Stream } ; pub mod built { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use hydroflow_lang :: graph :: { eliminate_extra_unions_tees , HydroflowGraph } ; pub use super :: deploy :: { DeployFlow , DeployResult } ; pub use crate :: deploy :: { ClusterSpec , Deploy , LocalDeploy , ProcessSpec } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Cluster , Process } ; pub use crate :: HfCompiled ; pub use crate :: builder :: built :: BuiltFlow ; # [cfg (stageleft_macro)] impl < 'a > Drop for BuiltFlow < 'a > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped BuiltFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn ir (& self) -> & Vec < HfPlusLeaf < 'a > > { & self . ir } pub fn optimize_with (mut self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> BuiltFlow < 'a > { self . used = true ; BuiltFlow { ir : f (std :: mem :: take (& mut self . ir)) , processes : std :: mem :: take (& mut self . processes) , clusters : std :: mem :: take (& mut self . clusters) , used : false , _phantom : PhantomData , } } } pub fn build_inner (ir : & mut Vec < HfPlusLeaf >) -> BTreeMap < usize , HydroflowGraph > { let mut builders = BTreeMap :: new () ; let mut built_tees = HashMap :: new () ; let mut next_stmt_id = 0 ; for leaf in ir { leaf . emit (& mut builders , & mut built_tees , & mut next_stmt_id) ; } builders . into_iter () . map (| (k , v) | { let (mut flat_graph , _ , _) = v . build () ; eliminate_extra_unions_tees (& mut flat_graph) ; (k , flat_graph) }) . collect () } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn compile_no_network < D : LocalDeploy < 'a > > (mut self) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; HfCompiled { hydroflow_ir : build_inner (& mut self . ir) , extra_stmts : BTreeMap :: new () , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> BuiltFlow < 'a > { self . optimize_with (crate :: persist_pullup :: persist_pullup) } fn into_deploy < D : LocalDeploy < 'a > > (mut self) -> DeployFlow < 'a , D > { self . used = true ; let processes = if D :: has_trivial_node () { self . processes . iter () . map (| id | (* id , D :: trivial_process (* id))) . collect () } else { HashMap :: new () } ; let clusters = if D :: has_trivial_node () { self . clusters . iter () . map (| id | (* id , D :: trivial_cluster (* id))) . collect () } else { HashMap :: new () } ; DeployFlow { ir : std :: mem :: take (& mut self . ir) , nodes : processes , clusters , used : false , _phantom : PhantomData , } } pub fn with_process < P , D : LocalDeploy < 'a > > (self , process : & Process < P > , spec : impl ProcessSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_process (process , spec) } pub fn with_cluster < C , D : LocalDeploy < 'a > > (self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_cluster (cluster , spec) } pub fn compile < D : Deploy < 'a > + 'a > (self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . into_deploy :: < D > () . compile (env) } pub fn deploy < D : Deploy < 'a , CompileEnv = () > + 'a > (self , env : & mut D :: InstantiateEnv ,) -> DeployResult < 'a , D > { self . into_deploy :: < D > () . deploy (env) } } } pub mod deploy { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use proc_macro2 :: Span ; pub use stageleft :: Quoted ; pub use super :: built :: build_inner ; pub use crate :: deploy :: { LocalDeploy , Node } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: { Cluster , ClusterSpec , Deploy , HfCompiled , Process , ProcessSpec } ; pub use crate :: builder :: deploy :: DeployFlow ; # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > Drop for DeployFlow < 'a , D > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped DeployFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > DeployFlow < 'a , D > { pub fn with_process < P > (mut self , process : & Process < P > , spec : impl ProcessSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < P > () . to_string () ; self . nodes . insert (process . id , spec . build (process . id , & tag_name)) ; self } pub fn with_cluster < C > (mut self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < C > () . to_string () ; self . clusters . insert (cluster . id , spec . build (cluster . id , & tag_name)) ; self } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployFlow < 'a , D > { pub fn compile (mut self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; let mut seen_tees : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | leaf . compile_network :: < D > (env , & mut seen_tees , & self . nodes , & self . clusters)) . collect () ; let extra_stmts = self . extra_stmts (env) ; HfCompiled { hydroflow_ir : build_inner (& mut ir_leaves_networked) , extra_stmts , _phantom : PhantomData , } } fn extra_stmts (& self , env : & < D as Deploy < 'a > > :: CompileEnv) -> BTreeMap < usize , Vec < syn :: Stmt > > { let all_locations_count = self . nodes . len () + self . clusters . len () ; let mut extra_stmts : BTreeMap < usize , Vec < syn :: Stmt > > = BTreeMap :: new () ; for & c_id in self . clusters . keys () { let self_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , c_id) , Span :: call_site () ,) ; let self_id_expr = D :: cluster_self_id (env) . splice () ; extra_stmts . entry (c_id) . or_default () . push (syn :: parse_quote ! { let # self_id_ident = # self_id_expr ; }) ; for other_location in 0 .. all_locations_count { let other_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , c_id) , Span :: call_site () ,) ; let other_id_expr = D :: cluster_ids (env , c_id) . splice () ; extra_stmts . entry (other_location) . or_default () . push (syn :: parse_quote ! { let # other_id_ident = # other_id_expr ; }) ; } } extra_stmts } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a , CompileEnv = () > > DeployFlow < 'a , D > { # [must_use] pub fn deploy (mut self , env : & mut D :: InstantiateEnv) -> DeployResult < 'a , D > { self . used = true ; let mut seen_tees_instantiate : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | { leaf . compile_network :: < D > (& () , & mut seen_tees_instantiate , & self . nodes , & self . clusters ,) }) . collect () ; let mut compiled = build_inner (& mut ir_leaves_networked) ; let mut extra_stmts = self . extra_stmts (& ()) ; let mut meta = D :: Meta :: default () ; let (mut processes , mut clusters) = (std :: mem :: take (& mut self . nodes) . into_iter () . map (| (node_id , node) | { node . instantiate (env , & mut meta , compiled . remove (& node_id) . unwrap () , extra_stmts . remove (& node_id) . unwrap_or_default () ,) ; (node_id , node) }) . collect :: < HashMap < _ , _ > > () , std :: mem :: take (& mut self . clusters) . into_iter () . map (| (cluster_id , cluster) | { cluster . instantiate (env , & mut meta , compiled . remove (& cluster_id) . unwrap () , extra_stmts . remove (& cluster_id) . unwrap_or_default () ,) ; (cluster_id , cluster) }) . collect :: < HashMap < _ , _ > > () ,) ; for node in processes . values_mut () { node . update_meta (& meta) ; } for cluster in clusters . values_mut () { cluster . update_meta (& meta) ; } let mut seen_tees_connect = HashMap :: new () ; for leaf in ir_leaves_networked { leaf . connect_network (& mut seen_tees_connect) ; } DeployResult { processes , clusters , } } } pub use crate :: builder :: deploy :: DeployResult ; # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployResult < 'a , D > { pub fn get_process < P > (& self , p : & Process < P >) -> & D :: Process { let id = match p . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . processes . get (& id) . unwrap () } pub fn get_cluster < C > (& self , c : & Cluster < C >) -> & D :: Cluster { let id = match c . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . clusters . get (& id) . unwrap () } } } # [doc = " Tracks the leaves of the dataflow IR. This is referenced by"] # [doc = " `Stream` and `HfCycle` to build the IR. The inner option will"] # [doc = " be set to `None` when this builder is finalized."] pub type FlowLeaves < 'a > = Rc < RefCell < Option < Vec < HfPlusLeaf < 'a > > > > > ; pub use crate :: builder :: ClusterIds ; # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Vec < u32 > > for ClusterIds < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , & 'a Vec < u32 > > for ClusterIds < 'a > { } # [derive (Copy , Clone)] pub struct ClusterSelfId < 'a > { pub id : usize , pub _phantom : PhantomData < & 'a mut & 'a u32 > , } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < u32 > for ClusterSelfId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , u32 > for ClusterSelfId < 'a > { } pub use crate :: builder :: FlowBuilder ; # [cfg (stageleft_macro)] impl < 'a > Drop for FlowBuilder < 'a > { fn drop (& mut self) { if ! self . finalized { panic ! ("Dropped FlowBuilder without finalizing, you may have forgotten to call `with_default_optimize`, `optimize_with`, or `finalize`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > QuotedContext for FlowBuilder < 'a > { fn create () -> Self { FlowBuilder :: new () } } # [cfg (stageleft_macro)] impl < 'a > FlowBuilder < 'a > { # [allow (clippy :: new_without_default)] pub fn new () -> FlowBuilder < 'a > { FlowBuilder { ir_leaves : Rc :: new (RefCell :: new (Some (Vec :: new ()))) , nodes : RefCell :: new (vec ! []) , clusters : RefCell :: new (vec ! []) , cycle_ids : RefCell :: new (HashMap :: new ()) , next_node_id : RefCell :: new (0) , finalized : false , _phantom : PhantomData , } } pub fn finalize (mut self) -> built :: BuiltFlow < 'a > { self . finalized = true ; built :: BuiltFlow { ir : self . ir_leaves . borrow_mut () . take () . unwrap () , processes : self . nodes . replace (vec ! []) , clusters : self . clusters . replace (vec ! []) , used : false , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> built :: BuiltFlow < 'a > { self . finalize () . with_default_optimize () } pub fn optimize_with (self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> built :: BuiltFlow < 'a > { self . finalize () . optimize_with (f) } pub fn ir_leaves (& self) -> & FlowLeaves < 'a > { & self . ir_leaves } pub fn process < P > (& self) -> Process < P > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . nodes . borrow_mut () . push (id) ; Process { id , _phantom : PhantomData , } } pub fn cluster < C > (& self) -> Cluster < C > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . clusters . borrow_mut () . push (id) ; Cluster { id , _phantom : PhantomData , } } pub fn runtime_context (& self) -> RuntimeContext < 'a > { RuntimeContext { _phantom : PhantomData , } } pub fn cluster_members < C > (& self , cluster : & Cluster < C > ,) -> impl Quoted < 'a , & 'a Vec < u32 > > + Copy + 'a { ClusterIds { id : cluster . id , _phantom : PhantomData , } } pub fn cluster_self_id < C > (& self , cluster : & Cluster < C >) -> impl Quoted < 'a , u32 > + Copy + 'a { ClusterSelfId { id : cluster . id , _phantom : PhantomData , } } pub fn spin < L : Location > (& self , on : & L) -> Stream < 'a , () , Unbounded , NoTick , L > { Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Spin () , location_kind : on . id () , })) ,) } pub fn spin_batch < L : Location > (& self , on : & L , batch_size : impl Quoted < 'a , usize > + Copy + 'a ,) -> Stream < 'a , () , Bounded , Tick , L > { self . spin (on) . flat_map (q ! (move | _ | 0 .. batch_size)) . map (q ! (| _ | ())) . tick_batch () } pub fn source_stream < T , E : FuturesStream < Item = T > + Unpin , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Unbounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Stream (e . into ()) , location_kind : on . id () , })) ,) } pub fn source_iter < T , E : IntoIterator < Item = T > , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Bounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , })) ,) } pub fn singleton < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Singleton < 'a , T , Bounded , NoTick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Singleton :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,)))) ,) } pub fn singleton_first_tick < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Optional < 'a , T , Bounded , Tick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,) } pub fn source_interval < L : Location > (& self , on : & L , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , () , Unbounded , NoTick , L > { let interval = interval . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : on . id () , })) ,) } pub fn source_interval_delayed < L : Location > (& self , on : & L , delay : impl Quoted < 'a , Duration > + Copy + 'a , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , tokio :: time :: Instant , Unbounded , NoTick , L > { self . source_stream (on , q ! (tokio_stream :: wrappers :: IntervalStream :: new (tokio :: time :: interval_at (tokio :: time :: Instant :: now () + delay , interval))) ,) . tick_batch () . first () . latest () } pub fn cycle < S : CycleCollection < 'a > > (& self , on : & S :: Location) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , on . id ()) ,) } pub fn cycle_with_initial < S : CycleCollectionWithInitial < 'a > > (& self , on : & S :: Location , initial : S ,) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , initial , on . id ()) ,) } } } pub use builder :: FlowBuilder ; pub mod ir { pub use core :: panic ; pub use std :: cell :: RefCell ; pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow_lang :: graph :: FlatGraphBuilder ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: ToTokens ; pub use syn :: parse_quote ; pub use crate :: deploy :: Deploy ; pub use crate :: location :: LocationId ; pub use crate :: ir :: DebugExpr ; # [cfg (stageleft_macro)] impl From < syn :: Expr > for DebugExpr { fn from (expr : syn :: Expr) -> DebugExpr { DebugExpr (expr) } } # [cfg (stageleft_macro)] impl Deref for DebugExpr { type Target = syn :: Expr ; fn deref (& self) -> & Self :: Target { & self . 0 } } # [cfg (stageleft_macro)] impl ToTokens for DebugExpr { fn to_tokens (& self , tokens : & mut TokenStream) { self . 0 . to_tokens (tokens) ; } } # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugExpr { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "{}" , self . 0 . to_token_stream ()) } } pub use crate :: ir :: DebugInstantiate ; # [cfg (stageleft_macro)] impl < 'a > std :: fmt :: Debug for DebugInstantiate < 'a > { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<network instantiate>") } } pub use crate :: ir :: DebugPipelineFn ; # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugPipelineFn { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<function>") } } pub use crate :: ir :: HfPlusSource ; pub use crate :: ir :: HfPlusLeaf ; # [cfg (stageleft_macro)] impl < 'a > HfPlusLeaf < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . compile_network :: < D > (compile_env , s , nodes , clusters) ; } , seen_tees ,) } pub fn connect_network (self , seen_tees : & mut SeenTees < 'a >) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . connect_network (s) ; } , seen_tees ,) } pub fn transform_children (self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) -> HfPlusLeaf < 'a > { match self { HfPlusLeaf :: ForEach { f , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: ForEach { f , input } } HfPlusLeaf :: DestSink { sink , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: DestSink { sink , input } } HfPlusLeaf :: CycleSink { ident , location_kind , mut input , } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: CycleSink { ident , location_kind , input , } } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) { match self { HfPlusLeaf :: ForEach { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> for_each (# f) ; }) ; } HfPlusLeaf :: DestSink { sink , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink) ; }) ; } HfPlusLeaf :: CycleSink { ident , location_kind , input , } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; assert_eq ! (input_location_id , * location_id , "cycle_sink location mismatch") ; graph_builders . entry (* location_id) . or_default () . add_statement (parse_quote ! { # ident = # input_ident ; }) ; } } } } pub use crate :: ir :: HfPlusNode ; pub type SeenTees < 'a > = HashMap < * const RefCell < HfPlusNode < 'a > > , Rc < RefCell < HfPlusNode < 'a > > > > ; # [cfg (stageleft_macro)] impl < 'a > HfPlusNode < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (& mut self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) { self . transform_children (| n , s | n . compile_network :: < D > (compile_env , s , nodes , clusters) , seen_tees ,) ; if let HfPlusNode :: Network { from_location , to_location , instantiate_fn , .. } = self { let (sink_expr , source_expr , connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { let ((sink , source) , connect_fn) = match (from_location , to_location) { (LocationId :: Process (from) , LocationId :: Process (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: o2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Process (from) , LocationId :: Cluster (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: o2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Process (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: m2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Cluster (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: m2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } } ; (sink , source , connect_fn) } DebugInstantiate :: Finalized (_ , _ , _) => panic ! ("network already finalized") , } ; * instantiate_fn = DebugInstantiate :: Finalized (sink_expr , source_expr , connect_fn) ; } } pub fn connect_network (& mut self , seen_tees : & mut SeenTees < 'a >) { self . transform_children (| n , s | n . connect_network (s) , seen_tees) ; if let HfPlusNode :: Network { instantiate_fn , .. } = self { match instantiate_fn { DebugInstantiate :: Building () => panic ! ("network not built") , DebugInstantiate :: Finalized (_ , _ , ref connect_fn) => { connect_fn () ; } } } } pub fn transform_children (& mut self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) { match self { HfPlusNode :: Placeholder => { panic ! () ; } HfPlusNode :: Source { .. } => { } HfPlusNode :: CycleSource { .. } => { } HfPlusNode :: Tee { inner } => { if let Some (transformed) = seen_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { * inner = transformed . clone () ; } else { let transformed_cell = Rc :: new (RefCell :: new (HfPlusNode :: Placeholder)) ; seen_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , transformed_cell . clone () ,) ; let mut orig = inner . replace (HfPlusNode :: Placeholder) ; transform (& mut orig , seen_tees) ; * transformed_cell . borrow_mut () = orig ; * inner = transformed_cell ; } } HfPlusNode :: Persist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Unpersist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Delta (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Union (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossProduct (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossSingleton (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Join (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Difference (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: AntiJoin (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Map { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FlatMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Filter { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FilterMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Sort (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: DeferTick (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Enumerate (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Inspect { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Unique (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Fold { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FoldKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Reduce { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: ReduceKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Network { input , .. } => { transform (input . as_mut () , seen_tees) ; } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) -> (syn :: Ident , usize) { match self { HfPlusNode :: Placeholder => { panic ! () } HfPlusNode :: Persist (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let persist_id = * next_stmt_id ; * next_stmt_id += 1 ; let persist_ident = syn :: Ident :: new (& format ! ("stream_{}" , persist_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # persist_ident = # inner_ident -> persist ::<'static > () ; }) ; (persist_ident , location) } HfPlusNode :: Unpersist (_) => { panic ! ("Unpersist is a marker node and should have been optimized away. This is likely a compiler bug.") } HfPlusNode :: Delta (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let delta_id = * next_stmt_id ; * next_stmt_id += 1 ; let delta_ident = syn :: Ident :: new (& format ! ("stream_{}" , delta_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # delta_ident = # inner_ident -> multiset_delta () ; }) ; (delta_ident , location) } HfPlusNode :: Source { source , location_kind , } => { let source_id = * next_stmt_id ; * next_stmt_id += 1 ; let source_ident = syn :: Ident :: new (& format ! ("stream_{}" , source_id) , Span :: call_site ()) ; let source_stmt = match source { HfPlusSource :: Stream (expr) => { parse_quote ! { # source_ident = source_stream (# expr) ; } } HfPlusSource :: Iter (expr) => { parse_quote ! { # source_ident = source_iter (# expr) ; } } HfPlusSource :: Interval (expr) => { parse_quote ! { # source_ident = source_interval (# expr) ; } } HfPlusSource :: Spin () => { parse_quote ! { # source_ident = spin () ; } } } ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; graph_builders . entry (* location_id) . or_default () . add_statement (source_stmt) ; (source_ident , * location_id) } HfPlusNode :: CycleSource { ident , location_kind , } => { let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; (ident . clone () , * location_id) } HfPlusNode :: Tee { inner } => { if let Some (ret) = built_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { ret . clone () } else { let (inner_ident , inner_location_id) = inner . borrow () . emit (graph_builders , built_tees , next_stmt_id) ; let tee_id = * next_stmt_id ; * next_stmt_id += 1 ; let tee_ident = syn :: Ident :: new (& format ! ("stream_{}" , tee_id) , Span :: call_site ()) ; let builder = graph_builders . entry (inner_location_id) . or_default () ; builder . add_statement (parse_quote ! { # tee_ident = # inner_ident -> tee () ; }) ; built_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , (tee_ident . clone () , inner_location_id) ,) ; (tee_ident , inner_location_id) } } HfPlusNode :: Union (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "union inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let union_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # union_ident = union () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [0] # union_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # union_ident ; }) ; (union_ident , left_location_id) } HfPlusNode :: CrossSingleton (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "cross_singleton inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let cross_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # cross_ident = cross_singleton () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [input] # cross_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [single] # cross_ident ; }) ; (cross_ident , left_location_id) } HfPlusNode :: CrossProduct (..) | HfPlusNode :: Join (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: CrossProduct (..)) { parse_quote ! (cross_join_multiset) } else { parse_quote ! (join_multiset) } ; let (HfPlusNode :: CrossProduct (left , right) | HfPlusNode :: Join (left , right)) = self else { unreachable ! () } ; let (left_inner , left_was_persist) = if let HfPlusNode :: Persist (left) = left . as_ref () { (left , true) } else { (left , false) } ; let (right_inner , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left_inner . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right_inner . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "join / cross product inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; match (left_was_persist , right_was_persist) { (true , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'static > () ; }) ; } (true , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'tick > () ; }) ; } (false , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } (false , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } } ; builder . add_statement (parse_quote ! { # left_ident -> [0] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Difference (..) | HfPlusNode :: AntiJoin (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Difference (..)) { parse_quote ! (difference_multiset) } else { parse_quote ! (anti_join_multiset) } ; let (HfPlusNode :: Difference (left , right) | HfPlusNode :: AntiJoin (left , right)) = self else { unreachable ! () } ; let (right , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "difference / anti join inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; if right_was_persist { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } else { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } builder . add_statement (parse_quote ! { # left_ident -> [pos] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [neg] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Map { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let map_id = * next_stmt_id ; * next_stmt_id += 1 ; let map_ident = syn :: Ident :: new (& format ! ("stream_{}" , map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # map_ident = # input_ident -> map (# f) ; }) ; (map_ident , input_location_id) } HfPlusNode :: FlatMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let flat_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let flat_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , flat_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # flat_map_ident = # input_ident -> flat_map (# f) ; }) ; (flat_map_ident , input_location_id) } HfPlusNode :: Filter { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_ident = # input_ident -> filter (# f) ; }) ; (filter_ident , input_location_id) } HfPlusNode :: FilterMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_map_ident = # input_ident -> filter_map (# f) ; }) ; (filter_map_ident , input_location_id) } HfPlusNode :: Sort (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sort_id = * next_stmt_id ; * next_stmt_id += 1 ; let sort_ident = syn :: Ident :: new (& format ! ("stream_{}" , sort_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # sort_ident = # input_ident -> sort () ; }) ; (sort_ident , input_location_id) } HfPlusNode :: DeferTick (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let defer_tick_id = * next_stmt_id ; * next_stmt_id += 1 ; let defer_tick_ident = syn :: Ident :: new (& format ! ("stream_{}" , defer_tick_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # defer_tick_ident = # input_ident -> defer_tick_lazy () ; }) ; (defer_tick_ident , input_location_id) } HfPlusNode :: Enumerate (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let enumerate_id = * next_stmt_id ; * next_stmt_id += 1 ; let enumerate_ident = syn :: Ident :: new (& format ! ("stream_{}" , enumerate_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # enumerate_ident = # input_ident -> enumerate () ; }) ; (enumerate_ident , input_location_id) } HfPlusNode :: Inspect { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let inspect_id = * next_stmt_id ; * next_stmt_id += 1 ; let inspect_ident = syn :: Ident :: new (& format ! ("stream_{}" , inspect_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # inspect_ident = # input_ident -> inspect (# f) ; }) ; (inspect_ident , input_location_id) } HfPlusNode :: Unique (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let unique_id = * next_stmt_id ; * next_stmt_id += 1 ; let unique_ident = syn :: Ident :: new (& format ! ("stream_{}" , unique_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # unique_ident = # input_ident -> unique ::<'tick > () ; }) ; (unique_ident , input_location_id) } HfPlusNode :: Fold { .. } | HfPlusNode :: FoldKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Fold { .. }) { parse_quote ! (fold) } else { parse_quote ! (fold_keyed) } ; let (HfPlusNode :: Fold { init , acc , input } | HfPlusNode :: FoldKeyed { init , acc , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let fold_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'static > (# init , # acc) ; }) ; } else { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'tick > (# init , # acc) ; }) ; } (fold_ident , input_location_id) } HfPlusNode :: Reduce { .. } | HfPlusNode :: ReduceKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Reduce { .. }) { parse_quote ! (reduce) } else { parse_quote ! (reduce_keyed) } ; let (HfPlusNode :: Reduce { f , input } | HfPlusNode :: ReduceKeyed { f , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let reduce_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'static > (# f) ; }) ; } else { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'tick > (# f) ; }) ; } (reduce_ident , input_location_id) } HfPlusNode :: Network { from_location : _ , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input , } => { let (sink_expr , source_expr , _connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { panic ! ("Expected the network to be finalized") } DebugInstantiate :: Finalized (sink , source , connect_fn) => { (sink , source , connect_fn) } } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sender_builder = graph_builders . entry (input_location_id) . or_default () ; if let Some (serialize_pipeline) = serialize_pipeline { sender_builder . add_statement (parse_quote ! { # input_ident -> # serialize_pipeline -> dest_sink (# sink_expr) ; }) ; } else { sender_builder . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink_expr) ; }) ; } let to_id = match to_location { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let receiver_builder = graph_builders . entry (* to_id) . or_default () ; let receiver_stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let receiver_stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , receiver_stream_id) , Span :: call_site ()) ; if let Some (deserialize_pipeline) = deserialize_pipeline { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) -> # deserialize_pipeline ; }) ; } else { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) ; }) ; } (receiver_stream_ident , * to_id) } } } } } pub mod persist_pullup { pub use std :: cell :: RefCell ; pub use std :: collections :: HashSet ; pub use std :: ops :: Deref ; pub use crate :: ir :: * ; pub fn persist_pullup_node < 'a > (node : & mut HfPlusNode < 'a > , seen_tees : & mut SeenTees < 'a > , persist_pulled_tees : & mut HashSet < * const RefCell < HfPlusNode < 'a > > > ,) { node . transform_children (| n , s | persist_pullup_node (n , s , persist_pulled_tees) , seen_tees ,) ; match node { HfPlusNode :: Unpersist (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Unpersist (box HfPlusNode :: Persist (deref!(behind_persist))) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Delta (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Delta (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Tee { inner } => { if persist_pulled_tees . contains (& (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >)) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } else { let inner_borrow = inner . borrow () ; if let HfPlusNode :: Persist (_) = inner_borrow . deref () { drop (inner_borrow) ; persist_pulled_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >) ; if let HfPlusNode :: Persist (box behind_persist) = inner . replace (HfPlusNode :: Placeholder) { * inner . borrow_mut () = behind_persist ; } else { unreachable ! () } * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } } } HfPlusNode :: Map { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Map { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Map { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: FlatMap { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: FlatMap { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: FlatMap { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Filter { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Filter { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Filter { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Network { input : box HfPlusNode :: Persist (_) , .. } => { if let HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Union (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Union (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Union (left , right))) ; } else { unreachable ! () } } HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: CrossProduct (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,) ,)))) ; } else { unreachable ! () } } HfPlusNode :: Join (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Join (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: Join (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,))))) ; } else { unreachable ! () } } _ => { } } } pub fn persist_pullup (ir : Vec < HfPlusLeaf >) -> Vec < HfPlusLeaf > { let mut seen_tees = Default :: default () ; let mut persist_pulled_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| n , s | persist_pullup_node (n , s , & mut persist_pulled_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn persist_pullup_through_map () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } # [test] fn persist_pullup_behind_tee () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; let before_tee = flow . source_iter (& process , q ! (0 .. 10)) . tick_batch () . persist () ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } } } pub mod profiler { pub use std :: cell :: RefCell ; pub use hydroflow :: futures :: channel :: mpsc :: UnboundedSender ; pub use stageleft :: * ; pub use crate as hydroflow_plus ; pub use crate :: ir :: * ; pub use crate :: RuntimeContext ; pub fn increment_counter (count : & mut u64) { * count += 1 ; } pub fn quoted_any_fn < 'a , F : Fn (& usize) + 'a , Q : IntoQuotedMut < 'a , F > > (q : Q) -> Q { q } # [doc = " Add a profiling node before each node to count the cardinality of its input"] pub fn add_profiling_node < 'a > (node : & mut HfPlusNode < 'a > , _context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > , id : & mut u32 , seen_tees : & mut SeenTees < 'a > ,) { let my_id = * id ; * id += 1 ; node . transform_children (| node , seen_tees | { add_profiling_node (node , _context , counters , counter_queue , id , seen_tees) } , seen_tees ,) ; let orig_node = std :: mem :: replace (node , HfPlusNode :: Placeholder) ; * node = HfPlusNode :: Inspect { f : quoted_any_fn (q ! ({ counter_queue . borrow () . unbounded_send ((my_id as usize , counters . borrow () [my_id as usize])) . unwrap () ; counters . borrow_mut () [my_id as usize] = 0 ; move | _ | { hydroflow_plus :: profiler :: increment_counter (& mut counters . borrow_mut () [my_id as usize] ,) ; } })) . splice () . into () , input : Box :: new (orig_node) , } } # [doc = " Count the cardinality of each input and periodically output to a file"] pub fn profiling < 'a > (ir : Vec < HfPlusLeaf < 'a > > , context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > ,) -> Vec < HfPlusLeaf < 'a > > { let mut id = 0 ; let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | { add_profiling_node (node , context , counters , counter_queue , & mut id , seen_tees) } , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn profiler_wrapping_all_operators () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let runtime_context = flow . runtime_context () ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (& built . ir ()) ; let counters = RuntimeData :: new ("Fake") ; let counter_queue = RuntimeData :: new ("Fake") ; let pushed_down = built . with_default_optimize () . optimize_with (| ir | super :: profiling (ir , runtime_context , counters , counter_queue)) ; insta :: assert_debug_snapshot ! (& pushed_down . ir ()) ; let _ = pushed_down . compile_no_network :: < MultiGraph > () ; } } } pub mod properties { pub use std :: collections :: HashSet ; pub use stageleft :: * ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , SeenTees } ; pub use crate :: properties :: PropertyDatabase ; # [doc = " Allows us to convert the hydroflow datatype for folds to a binary operation for the algebra"] # [doc = " property tests."] # [allow (dead_code)] pub fn convert_hf_to_binary < I , A : Default , F : Fn (& mut A , I) > (f : F) -> impl Fn (I , I) -> A { move | a , b | { let mut acc = Default :: default () ; f (& mut acc , a) ; f (& mut acc , b) ; acc } } # [cfg (stageleft_macro)] impl PropertyDatabase { # [doc = " Tags the expression as commutative."] pub fn add_commutative_tag < 'a , I , A , F : Fn (& mut A , I) , Q : Quoted < 'a , F > + Clone > (& mut self , expr : Q ,) -> Q { let expr_clone = expr . clone () ; self . commutative . insert (expr_clone . splice ()) ; expr } pub fn is_tagged_commutative (& self , expr : & syn :: Expr) -> bool { self . commutative . contains (expr) } } pub fn properties_optimize_node < 'a > (node : & mut HfPlusNode < 'a > , db : & PropertyDatabase , seen_tees : & mut SeenTees < 'a > ,) { node . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , seen_tees ,) ; match node { HfPlusNode :: ReduceKeyed { f , .. } if db . is_tagged_commutative (& f . 0) => { dbg ! ("IDENTIFIED COMMUTATIVE OPTIMIZATION for {:?}" , & f) ; } _ => { } } } pub fn properties_optimize < 'a > (ir : Vec < HfPlusLeaf < 'a > > , db : & PropertyDatabase ,) -> Vec < HfPlusLeaf < 'a > > { let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use super :: * ; use crate :: deploy :: SingleProcessGraph ; use crate :: FlowBuilder ; # [test] fn test_property_database () { let mut db = PropertyDatabase :: default () ; assert ! (! db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; let _ = db . add_commutative_tag (q ! (| a : & mut i32 , b : i32 | * a += b)) ; assert ! (db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; } # [test] fn test_property_optimized () { let flow = FlowBuilder :: new () ; let mut database = PropertyDatabase :: default () ; let process = flow . process :: < () > () ; let counter_func = q ! (| count : & mut i32 , _ | * count += 1) ; let _ = database . add_commutative_tag (counter_func) ; flow . source_iter (& process , q ! (vec ! [])) . map (q ! (| string : String | (string , ()))) . tick_batch () . fold_keyed (q ! (|| 0) , counter_func) . all_ticks () . for_each (q ! (| (string , count) | println ! ("{}: {}" , string , count))) ; let built = flow . finalize () . optimize_with (| ir | properties_optimize (ir , & database)) . with_default_optimize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let _ = built . compile_no_network :: < SingleProcessGraph > () ; } } } pub use crate :: RuntimeContext ; # [cfg (stageleft_macro)] impl Copy for RuntimeContext < '_ > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Context > for RuntimeContext < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (quote ! (& context))) } } pub use crate :: HfCompiled ; # [cfg (stageleft_macro)] impl < 'a , ID > HfCompiled < 'a , ID > { pub fn hydroflow_ir (& self) -> & BTreeMap < usize , HydroflowGraph > { & self . hydroflow_ir } } # [cfg (stageleft_macro)] impl < 'a > HfCompiled < 'a , usize > { pub fn with_dynamic_id (self , id : impl Quoted < 'a , usize >) -> HfBuiltWithId < 'a > { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; let mut conditioned_tokens = None ; for (subgraph_id , flat_graph) in self . hydroflow_ir { let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; let my_extra_stmts = self . extra_stmts . get (& subgraph_id) . cloned () . unwrap_or_default () ; if let Some (conditioned_tokens) = conditioned_tokens . as_mut () { * conditioned_tokens = syn :: parse_quote ! { # conditioned_tokens else if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } } ; } else { conditioned_tokens = Some (syn :: parse_quote ! { if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } }) ; } } let conditioned_tokens : TokenStream = conditioned_tokens . unwrap () ; let id = id . splice () ; HfBuiltWithId { tokens : syn :: parse_quote ! ({ let __given_id = # id ; # conditioned_tokens else { panic ! ("Invalid node id: {}" , __given_id) ; } }) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfCompiled < 'a , () > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfCompiled < 'a , () > { fn to_tokens (mut self) -> (Option < TokenStream > , Option < TokenStream >) { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; if self . hydroflow_ir . len () != 1 { panic ! ("Expected exactly one subgraph in the Hydroflow IR") ; } let flat_graph = self . hydroflow_ir . remove (& 0) . unwrap () ; let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; (None , Some (tokens)) } } pub use crate :: HfBuiltWithId ; # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfBuiltWithId < 'a > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfBuiltWithId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (self . tokens)) } }
[INFO] [stdout]   |
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] error: `box` patterns have been removed (feature `box_patterns`)
[INFO] [stdout]  --> /opt/rustwide/target/debug/build/hydroflow_plus/5672655b657d1e44/out/lib_pub.rs:1:91851
[INFO] [stdout]   |
[INFO] [stdout] 1 | ...fPlusNode :: Persist (_)) => { if let HfPlusNode :: Unpersist (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: rep...
[INFO] [stdout]   |                                                                   ^^^
[INFO] [stdout]   |
[INFO] [stdout]   = help: enable feature `deref_patterns` instead and...
[INFO] [stdout] help: ...if possible just remove keyword `box`...
[INFO] [stdout]   |
[INFO] [stdout] 1 - pub use std :: collections :: BTreeMap ; pub use std :: marker :: PhantomData ; pub use hydroflow :: scheduled :: context :: Context ; pub use hydroflow :: scheduled :: graph :: Hydroflow ; pub use hydroflow :: * ; pub use lang :: graph :: { partition_graph , HydroflowGraph } ; pub use proc_macro2 :: TokenStream ; pub use quote :: quote ; pub use stageleft :: runtime_support :: FreeVariable ; pub use stageleft :: Quoted ; pub mod runtime_support { pub use bincode ; } pub mod stream { pub use std :: cell :: RefCell ; pub use std :: hash :: Hash ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow :: bytes :: Bytes ; pub use hydroflow :: futures :: Sink ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: quote ; pub use serde :: de :: DeserializeOwned ; pub use serde :: Serialize ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use syn :: parse_quote ; pub use crate :: builder :: { ClusterIds , FlowLeaves } ; pub use crate :: cycle :: { CycleCollection , CycleComplete } ; pub use crate :: ir :: { DebugInstantiate , HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { CanSend , Location , LocationId } ; pub use crate :: { Cluster , Optional , Singleton } ; pub use crate :: stream :: Unbounded ; pub use crate :: stream :: Bounded ; pub use crate :: stream :: NoTick ; pub use crate :: stream :: Tick ; pub use crate :: stream :: Stream ; # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Stream { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Stream < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Stream { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , C , N > > ,) -> Stream < 'a , (T , O) , W , C , N > where O : Clone , { let other : Optional < 'a , O , Bounded , C , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn cross_product < O > (self , other : Stream < 'a , O , W , C , N >) -> Stream < 'a , (T , O) , W , C , N > where T : Clone , O : Clone , { if self . location_kind != other . location_kind { panic ! ("cross_product must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossProduct (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn union (self , other : Stream < 'a , T , W , C , N >) -> Stream < 'a , T , W , C , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn dest_sink < S : Unpin + Sink < T > + 'a > (self , sink : impl Quoted < 'a , S >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: DestSink { sink : sink . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn first (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } # [doc = " Allow this stream through if the other stream has elements, otherwise the output is empty."] pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } # [doc = " Allow this stream through if the other stream is empty, otherwise the output is empty."] pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn enumerate (self) -> Stream < 'a , (usize , T) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Enumerate (Box :: new (self . ir_node . into_inner ())) ,) } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn sort (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Ord , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Sort (Box :: new (self . ir_node . into_inner ())) ,) } pub fn count (self) -> Singleton < 'a , usize , Bounded , Tick , N > { self . fold (q ! (|| 0usize) , q ! (| count , _ | * count += 1)) } pub fn delta (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } pub fn unique (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Eq + Hash , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unique (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn tick_batch (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_prefix (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { self . tick_batch () . persist () } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn for_each < F : Fn (T) + 'a > (self , f : impl IntoQuotedMut < 'a , F >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: ForEach { input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , f : f . splice () . into () , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Unbounded , NoTick , N > { pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . tick_batch () . continue_if (samples . first ()) . all_ticks () } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Unbounded , NoTick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , C , N : Location > Stream < 'a , T , Bounded , C , N > { pub fn filter_not_in (self , other : Stream < 'a , T , Bounded , C , N >) -> Stream < 'a , T , Bounded , C , N > where T : Eq + Hash , { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Difference (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Stream < 'a , & T , W , C , N > { pub fn cloned (self) -> Stream < 'a , T , W , C , N > { self . map (q ! (| d | d . clone ())) } } # [cfg (stageleft_macro)] impl < 'a , K , V1 , W , C , N : Location > Stream < 'a , (K , V1) , W , C , N > { pub fn join < W2 , V2 > (self , n : Stream < 'a , (K , V2) , W2 , C , N > ,) -> Stream < 'a , (K , (V1 , V2)) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Join (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } pub fn anti_join < W2 > (self , n : Stream < 'a , K , W2 , C , N >) -> Stream < 'a , (K , V1) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("anti_join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: AntiJoin (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , K : Eq + Hash , V , N : Location > Stream < 'a , (K , V) , Bounded , Tick , N > { pub fn fold_keyed < A , I : Fn () -> A + 'a , F : Fn (& mut A , V) + 'a > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , A) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FoldKeyed { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce_keyed < F : Fn (& mut V , V) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , V) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: ReduceKeyed { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } pub fn get_this_crate () -> TokenStream { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , Span :: call_site ()) ; quote ! { # ident } } } } pub fn serialize_bincode < T : Serialize > (is_demux : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if is_demux { parse_quote ! { map (| (id , data) | { (id , # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into ()) }) } } else { parse_quote ! { map (| data | { # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into () }) } } } pub fn deserialize_bincode < T : DeserializeOwned > (tagged : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if tagged { parse_quote ! { map (| res | { let (id , b) = res . unwrap () ; (id , # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& b) . unwrap ()) }) } } else { parse_quote ! { map (| res | { # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& res . unwrap ()) . unwrap () }) } } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn send_bincode < N2 : Location , CoreType > (self , other : & N2 ,) -> Stream < 'a , N :: Out < CoreType > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T > , CoreType : Serialize + DeserializeOwned , { let serialize_pipeline = Some (serialize_bincode :: < CoreType > (N :: is_demux ())) ; let deserialize_pipeline = Some (deserialize_bincode :: < CoreType > (N :: is_tagged ())) ; Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bytes < N2 : Location > (self , other : & N2 ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T > , { Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline : None , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline : if N :: is_tagged () { Some (parse_quote ! (map (| (id , b) | (id , b . unwrap () . freeze ())))) } else { Some (parse_quote ! (map (| b | b . unwrap () . freeze ()))) } , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bincode_interleaved < N2 : Location , Tag , CoreType > (self , other : & N2 ,) -> Stream < 'a , CoreType , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T , Out < CoreType > = (Tag , CoreType) > , CoreType : Serialize + DeserializeOwned , { self . send_bincode :: < N2 , CoreType > (other) . map (q ! (| (_ , b) | b)) } pub fn send_bytes_interleaved < N2 : Location , Tag > (self , other : & N2 ,) -> Stream < 'a , Bytes , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T , Out < Bytes > = (Tag , Bytes) > , { self . send_bytes :: < N2 > (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bincode < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < T > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) > , T : Clone + Serialize + DeserializeOwned , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bincode (other) } pub fn broadcast_bincode_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , T , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) , Out < T > = (Tag , T) > + 'a , T : Clone + Serialize + DeserializeOwned , { self . broadcast_bincode (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bytes < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) > + 'a , T : Clone , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bytes (other) } pub fn broadcast_bytes_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , Bytes , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) , Out < Bytes > = (Tag , Bytes) > + 'a , T : Clone , { self . broadcast_bytes (other) . map (q ! (| (_ , b) | b)) } } } pub use stream :: { Bounded , NoTick , Stream , Tick , Unbounded } ; pub mod singleton { pub use std :: cell :: RefCell ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use crate :: builder :: FlowLeaves ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial , CycleComplete } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: Stream ; pub use crate :: singleton :: CrossResult ; # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Singleton < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Singleton :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } pub use crate :: singleton :: Singleton ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Singleton { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleComplete < 'a > for Singleton < 'a , T , Bounded , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleCollectionWithInitial < 'a > for Singleton < 'a , T , Bounded , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , initial : Self , l : LocationId ,) -> Self { Singleton :: new (l , ir_leaves , HfPlusNode :: Union (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , }) , initial . ir_node . into_inner () . into () ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Singleton < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Singleton { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , U , W , C , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (Self :: other_ir_node (other)) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Singleton < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CrossSingleton (Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , Box :: new (HfPlusNode :: Unpersist (Box :: new (Self :: other_ir_node (other)))) ,))) ,) } } pub use crate :: singleton :: Optional ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Optional { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } pub fn some (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: new (singleton . location_kind , singleton . ir_leaves , singleton . ir_node . into_inner () ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > From < Singleton < 'a , T , W , C , N > > for Optional < 'a , T , W , C , N > { fn from (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: some (singleton) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Optional < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Optional { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn into_stream (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , Tick , N > > ,) -> Optional < 'a , (T , O) , Bounded , Tick , N > where O : Clone , { let other : Optional < 'a , O , Bounded , Tick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn union (self , other : Optional < 'a , T , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Optional < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_samples (self) -> Stream < 'a , T , Unbounded , NoTick , N > { self . latest_tick () . all_ticks () } pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . latest_tick () . continue_if (samples . first ()) . latest () . tick_samples () } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Unbounded , NoTick , N > > ,) -> Optional < 'a , (T , O) , Unbounded , NoTick , N > where O : Clone , { let other : Optional < 'a , O , Unbounded , NoTick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } self . latest_tick () . cross_singleton (other . latest_tick ()) . latest () } } } pub use singleton :: { Optional , Singleton } ; pub mod location { pub use std :: marker :: PhantomData ; pub use crate :: location :: LocationId ; pub use crate :: location :: Location ; pub use crate :: location :: Process ; # [cfg (stageleft_macro)] impl < P > Clone for Process < P > { fn clone (& self) -> Self { Process { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < P > Location for Process < P > { fn id (& self) -> LocationId { LocationId :: Process (self . id) } } pub use crate :: location :: Cluster ; # [cfg (stageleft_macro)] impl < C > Clone for Cluster < C > { fn clone (& self) -> Self { Cluster { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < C > Location for Cluster < C > { fn id (& self) -> LocationId { LocationId :: Cluster (self . id) } } pub use crate :: location :: CanSend ; # [cfg (stageleft_macro)] impl < P1 , P2 > CanSend < Process < P2 > > for Process < P1 > { type In < T > = T ; type Out < T > = T ; fn is_demux () -> bool { false } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < P1 , C2 > CanSend < Cluster < C2 > > for Process < P1 > { type In < T > = (u32 , T) ; type Out < T > = T ; fn is_demux () -> bool { true } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < C1 , P2 > CanSend < Process < P2 > > for Cluster < C1 > { type In < T > = T ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { false } fn is_tagged () -> bool { true } } # [cfg (stageleft_macro)] impl < C1 , C2 > CanSend < Cluster < C2 > > for Cluster < C1 > { type In < T > = (u32 , T) ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { true } fn is_tagged () -> bool { true } } } pub use location :: { Cluster , Process } ; pub mod deploy { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use stageleft :: Quoted ; pub mod graphs { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use super :: { LocalDeploy , Node , ProcessSpec } ; pub use crate :: deploy :: graphs :: SingleProcessGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for SingleProcessGraph { type Process = SingleNode ; type Cluster = SingleNode ; type Meta = () ; type GraphId = () ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { SingleNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { SingleNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , SingleProcessGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> SingleNode { SingleNode { } } } pub use crate :: deploy :: graphs :: SingleNode ; # [cfg (stageleft_macro)] impl Node for SingleNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } pub use crate :: deploy :: graphs :: MultiGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for MultiGraph { type Process = MultiNode ; type Cluster = MultiNode ; type Meta = () ; type GraphId = usize ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { MultiNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { MultiNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , MultiGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> MultiNode { MultiNode { } } } pub use crate :: deploy :: graphs :: MultiNode ; # [cfg (stageleft_macro)] impl Node for MultiNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } } pub use graphs :: * ; pub use crate :: deploy :: LocalDeploy ; pub use crate :: deploy :: Deploy ; # [cfg (stageleft_macro)] impl < 'a , T : Deploy < 'a , Process = N , Cluster = C , Meta = M , GraphId = R > , N : Node < Meta = M > , C : Node < Meta = M > , M : Default , R , > LocalDeploy < 'a > for T { type Process = N ; type Cluster = C ; type Meta = M ; type GraphId = R ; fn has_trivial_node () -> bool { < T as Deploy < 'a > > :: has_trivial_node () } fn trivial_process (id : usize) -> Self :: Process { < T as Deploy < 'a > > :: trivial_process (id) } fn trivial_cluster (id : usize) -> Self :: Cluster { < T as Deploy < 'a > > :: trivail_cluster (id) } } pub use crate :: deploy :: ProcessSpec ; pub use crate :: deploy :: ClusterSpec ; pub use crate :: deploy :: Node ; } pub use deploy :: { ClusterSpec , Deploy , ProcessSpec } ; pub mod cycle { pub use std :: marker :: PhantomData ; pub use crate :: builder :: FlowLeaves ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: cycle :: CycleComplete ; pub use crate :: cycle :: CycleCollection ; pub use crate :: cycle :: CycleCollectionWithInitial ; pub use crate :: cycle :: HfCycle ; # [cfg (stageleft_macro)] impl < 'a , S : CycleComplete < 'a > > HfCycle < 'a , S > { pub fn complete (self , stream : S) { let ident = self . ident ; S :: complete (stream , ident) } } } pub use cycle :: HfCycle ; pub mod builder { pub use std :: cell :: RefCell ; pub use std :: collections :: HashMap ; pub use std :: marker :: PhantomData ; pub use std :: rc :: Rc ; pub use std :: time :: Duration ; pub use hydroflow :: futures :: stream :: Stream as FuturesStream ; pub use hydroflow :: { tokio , tokio_stream } ; pub use internal :: TokenStream ; pub use proc_macro2 :: Span ; pub use quote :: quote ; pub use runtime_support :: FreeVariable ; pub use stageleft :: * ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Cluster , Location , LocationId , Process } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: { HfCycle , Optional , RuntimeContext , Singleton , Stream } ; pub mod built { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use hydroflow_lang :: graph :: { eliminate_extra_unions_tees , HydroflowGraph } ; pub use super :: deploy :: { DeployFlow , DeployResult } ; pub use crate :: deploy :: { ClusterSpec , Deploy , LocalDeploy , ProcessSpec } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Cluster , Process } ; pub use crate :: HfCompiled ; pub use crate :: builder :: built :: BuiltFlow ; # [cfg (stageleft_macro)] impl < 'a > Drop for BuiltFlow < 'a > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped BuiltFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn ir (& self) -> & Vec < HfPlusLeaf < 'a > > { & self . ir } pub fn optimize_with (mut self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> BuiltFlow < 'a > { self . used = true ; BuiltFlow { ir : f (std :: mem :: take (& mut self . ir)) , processes : std :: mem :: take (& mut self . processes) , clusters : std :: mem :: take (& mut self . clusters) , used : false , _phantom : PhantomData , } } } pub fn build_inner (ir : & mut Vec < HfPlusLeaf >) -> BTreeMap < usize , HydroflowGraph > { let mut builders = BTreeMap :: new () ; let mut built_tees = HashMap :: new () ; let mut next_stmt_id = 0 ; for leaf in ir { leaf . emit (& mut builders , & mut built_tees , & mut next_stmt_id) ; } builders . into_iter () . map (| (k , v) | { let (mut flat_graph , _ , _) = v . build () ; eliminate_extra_unions_tees (& mut flat_graph) ; (k , flat_graph) }) . collect () } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn compile_no_network < D : LocalDeploy < 'a > > (mut self) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; HfCompiled { hydroflow_ir : build_inner (& mut self . ir) , extra_stmts : BTreeMap :: new () , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> BuiltFlow < 'a > { self . optimize_with (crate :: persist_pullup :: persist_pullup) } fn into_deploy < D : LocalDeploy < 'a > > (mut self) -> DeployFlow < 'a , D > { self . used = true ; let processes = if D :: has_trivial_node () { self . processes . iter () . map (| id | (* id , D :: trivial_process (* id))) . collect () } else { HashMap :: new () } ; let clusters = if D :: has_trivial_node () { self . clusters . iter () . map (| id | (* id , D :: trivial_cluster (* id))) . collect () } else { HashMap :: new () } ; DeployFlow { ir : std :: mem :: take (& mut self . ir) , nodes : processes , clusters , used : false , _phantom : PhantomData , } } pub fn with_process < P , D : LocalDeploy < 'a > > (self , process : & Process < P > , spec : impl ProcessSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_process (process , spec) } pub fn with_cluster < C , D : LocalDeploy < 'a > > (self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_cluster (cluster , spec) } pub fn compile < D : Deploy < 'a > + 'a > (self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . into_deploy :: < D > () . compile (env) } pub fn deploy < D : Deploy < 'a , CompileEnv = () > + 'a > (self , env : & mut D :: InstantiateEnv ,) -> DeployResult < 'a , D > { self . into_deploy :: < D > () . deploy (env) } } } pub mod deploy { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use proc_macro2 :: Span ; pub use stageleft :: Quoted ; pub use super :: built :: build_inner ; pub use crate :: deploy :: { LocalDeploy , Node } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: { Cluster , ClusterSpec , Deploy , HfCompiled , Process , ProcessSpec } ; pub use crate :: builder :: deploy :: DeployFlow ; # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > Drop for DeployFlow < 'a , D > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped DeployFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > DeployFlow < 'a , D > { pub fn with_process < P > (mut self , process : & Process < P > , spec : impl ProcessSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < P > () . to_string () ; self . nodes . insert (process . id , spec . build (process . id , & tag_name)) ; self } pub fn with_cluster < C > (mut self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < C > () . to_string () ; self . clusters . insert (cluster . id , spec . build (cluster . id , & tag_name)) ; self } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployFlow < 'a , D > { pub fn compile (mut self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; let mut seen_tees : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | leaf . compile_network :: < D > (env , & mut seen_tees , & self . nodes , & self . clusters)) . collect () ; let extra_stmts = self . extra_stmts (env) ; HfCompiled { hydroflow_ir : build_inner (& mut ir_leaves_networked) , extra_stmts , _phantom : PhantomData , } } fn extra_stmts (& self , env : & < D as Deploy < 'a > > :: CompileEnv) -> BTreeMap < usize , Vec < syn :: Stmt > > { let all_locations_count = self . nodes . len () + self . clusters . len () ; let mut extra_stmts : BTreeMap < usize , Vec < syn :: Stmt > > = BTreeMap :: new () ; for & c_id in self . clusters . keys () { let self_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , c_id) , Span :: call_site () ,) ; let self_id_expr = D :: cluster_self_id (env) . splice () ; extra_stmts . entry (c_id) . or_default () . push (syn :: parse_quote ! { let # self_id_ident = # self_id_expr ; }) ; for other_location in 0 .. all_locations_count { let other_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , c_id) , Span :: call_site () ,) ; let other_id_expr = D :: cluster_ids (env , c_id) . splice () ; extra_stmts . entry (other_location) . or_default () . push (syn :: parse_quote ! { let # other_id_ident = # other_id_expr ; }) ; } } extra_stmts } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a , CompileEnv = () > > DeployFlow < 'a , D > { # [must_use] pub fn deploy (mut self , env : & mut D :: InstantiateEnv) -> DeployResult < 'a , D > { self . used = true ; let mut seen_tees_instantiate : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | { leaf . compile_network :: < D > (& () , & mut seen_tees_instantiate , & self . nodes , & self . clusters ,) }) . collect () ; let mut compiled = build_inner (& mut ir_leaves_networked) ; let mut extra_stmts = self . extra_stmts (& ()) ; let mut meta = D :: Meta :: default () ; let (mut processes , mut clusters) = (std :: mem :: take (& mut self . nodes) . into_iter () . map (| (node_id , node) | { node . instantiate (env , & mut meta , compiled . remove (& node_id) . unwrap () , extra_stmts . remove (& node_id) . unwrap_or_default () ,) ; (node_id , node) }) . collect :: < HashMap < _ , _ > > () , std :: mem :: take (& mut self . clusters) . into_iter () . map (| (cluster_id , cluster) | { cluster . instantiate (env , & mut meta , compiled . remove (& cluster_id) . unwrap () , extra_stmts . remove (& cluster_id) . unwrap_or_default () ,) ; (cluster_id , cluster) }) . collect :: < HashMap < _ , _ > > () ,) ; for node in processes . values_mut () { node . update_meta (& meta) ; } for cluster in clusters . values_mut () { cluster . update_meta (& meta) ; } let mut seen_tees_connect = HashMap :: new () ; for leaf in ir_leaves_networked { leaf . connect_network (& mut seen_tees_connect) ; } DeployResult { processes , clusters , } } } pub use crate :: builder :: deploy :: DeployResult ; # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployResult < 'a , D > { pub fn get_process < P > (& self , p : & Process < P >) -> & D :: Process { let id = match p . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . processes . get (& id) . unwrap () } pub fn get_cluster < C > (& self , c : & Cluster < C >) -> & D :: Cluster { let id = match c . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . clusters . get (& id) . unwrap () } } } # [doc = " Tracks the leaves of the dataflow IR. This is referenced by"] # [doc = " `Stream` and `HfCycle` to build the IR. The inner option will"] # [doc = " be set to `None` when this builder is finalized."] pub type FlowLeaves < 'a > = Rc < RefCell < Option < Vec < HfPlusLeaf < 'a > > > > > ; pub use crate :: builder :: ClusterIds ; # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Vec < u32 > > for ClusterIds < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , & 'a Vec < u32 > > for ClusterIds < 'a > { } # [derive (Copy , Clone)] pub struct ClusterSelfId < 'a > { pub id : usize , pub _phantom : PhantomData < & 'a mut & 'a u32 > , } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < u32 > for ClusterSelfId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , u32 > for ClusterSelfId < 'a > { } pub use crate :: builder :: FlowBuilder ; # [cfg (stageleft_macro)] impl < 'a > Drop for FlowBuilder < 'a > { fn drop (& mut self) { if ! self . finalized { panic ! ("Dropped FlowBuilder without finalizing, you may have forgotten to call `with_default_optimize`, `optimize_with`, or `finalize`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > QuotedContext for FlowBuilder < 'a > { fn create () -> Self { FlowBuilder :: new () } } # [cfg (stageleft_macro)] impl < 'a > FlowBuilder < 'a > { # [allow (clippy :: new_without_default)] pub fn new () -> FlowBuilder < 'a > { FlowBuilder { ir_leaves : Rc :: new (RefCell :: new (Some (Vec :: new ()))) , nodes : RefCell :: new (vec ! []) , clusters : RefCell :: new (vec ! []) , cycle_ids : RefCell :: new (HashMap :: new ()) , next_node_id : RefCell :: new (0) , finalized : false , _phantom : PhantomData , } } pub fn finalize (mut self) -> built :: BuiltFlow < 'a > { self . finalized = true ; built :: BuiltFlow { ir : self . ir_leaves . borrow_mut () . take () . unwrap () , processes : self . nodes . replace (vec ! []) , clusters : self . clusters . replace (vec ! []) , used : false , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> built :: BuiltFlow < 'a > { self . finalize () . with_default_optimize () } pub fn optimize_with (self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> built :: BuiltFlow < 'a > { self . finalize () . optimize_with (f) } pub fn ir_leaves (& self) -> & FlowLeaves < 'a > { & self . ir_leaves } pub fn process < P > (& self) -> Process < P > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . nodes . borrow_mut () . push (id) ; Process { id , _phantom : PhantomData , } } pub fn cluster < C > (& self) -> Cluster < C > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . clusters . borrow_mut () . push (id) ; Cluster { id , _phantom : PhantomData , } } pub fn runtime_context (& self) -> RuntimeContext < 'a > { RuntimeContext { _phantom : PhantomData , } } pub fn cluster_members < C > (& self , cluster : & Cluster < C > ,) -> impl Quoted < 'a , & 'a Vec < u32 > > + Copy + 'a { ClusterIds { id : cluster . id , _phantom : PhantomData , } } pub fn cluster_self_id < C > (& self , cluster : & Cluster < C >) -> impl Quoted < 'a , u32 > + Copy + 'a { ClusterSelfId { id : cluster . id , _phantom : PhantomData , } } pub fn spin < L : Location > (& self , on : & L) -> Stream < 'a , () , Unbounded , NoTick , L > { Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Spin () , location_kind : on . id () , })) ,) } pub fn spin_batch < L : Location > (& self , on : & L , batch_size : impl Quoted < 'a , usize > + Copy + 'a ,) -> Stream < 'a , () , Bounded , Tick , L > { self . spin (on) . flat_map (q ! (move | _ | 0 .. batch_size)) . map (q ! (| _ | ())) . tick_batch () } pub fn source_stream < T , E : FuturesStream < Item = T > + Unpin , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Unbounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Stream (e . into ()) , location_kind : on . id () , })) ,) } pub fn source_iter < T , E : IntoIterator < Item = T > , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Bounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , })) ,) } pub fn singleton < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Singleton < 'a , T , Bounded , NoTick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Singleton :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,)))) ,) } pub fn singleton_first_tick < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Optional < 'a , T , Bounded , Tick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,) } pub fn source_interval < L : Location > (& self , on : & L , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , () , Unbounded , NoTick , L > { let interval = interval . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : on . id () , })) ,) } pub fn source_interval_delayed < L : Location > (& self , on : & L , delay : impl Quoted < 'a , Duration > + Copy + 'a , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , tokio :: time :: Instant , Unbounded , NoTick , L > { self . source_stream (on , q ! (tokio_stream :: wrappers :: IntervalStream :: new (tokio :: time :: interval_at (tokio :: time :: Instant :: now () + delay , interval))) ,) . tick_batch () . first () . latest () } pub fn cycle < S : CycleCollection < 'a > > (& self , on : & S :: Location) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , on . id ()) ,) } pub fn cycle_with_initial < S : CycleCollectionWithInitial < 'a > > (& self , on : & S :: Location , initial : S ,) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , initial , on . id ()) ,) } } } pub use builder :: FlowBuilder ; pub mod ir { pub use core :: panic ; pub use std :: cell :: RefCell ; pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow_lang :: graph :: FlatGraphBuilder ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: ToTokens ; pub use syn :: parse_quote ; pub use crate :: deploy :: Deploy ; pub use crate :: location :: LocationId ; pub use crate :: ir :: DebugExpr ; # [cfg (stageleft_macro)] impl From < syn :: Expr > for DebugExpr { fn from (expr : syn :: Expr) -> DebugExpr { DebugExpr (expr) } } # [cfg (stageleft_macro)] impl Deref for DebugExpr { type Target = syn :: Expr ; fn deref (& self) -> & Self :: Target { & self . 0 } } # [cfg (stageleft_macro)] impl ToTokens for DebugExpr { fn to_tokens (& self , tokens : & mut TokenStream) { self . 0 . to_tokens (tokens) ; } } # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugExpr { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "{}" , self . 0 . to_token_stream ()) } } pub use crate :: ir :: DebugInstantiate ; # [cfg (stageleft_macro)] impl < 'a > std :: fmt :: Debug for DebugInstantiate < 'a > { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<network instantiate>") } } pub use crate :: ir :: DebugPipelineFn ; # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugPipelineFn { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<function>") } } pub use crate :: ir :: HfPlusSource ; pub use crate :: ir :: HfPlusLeaf ; # [cfg (stageleft_macro)] impl < 'a > HfPlusLeaf < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . compile_network :: < D > (compile_env , s , nodes , clusters) ; } , seen_tees ,) } pub fn connect_network (self , seen_tees : & mut SeenTees < 'a >) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . connect_network (s) ; } , seen_tees ,) } pub fn transform_children (self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) -> HfPlusLeaf < 'a > { match self { HfPlusLeaf :: ForEach { f , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: ForEach { f , input } } HfPlusLeaf :: DestSink { sink , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: DestSink { sink , input } } HfPlusLeaf :: CycleSink { ident , location_kind , mut input , } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: CycleSink { ident , location_kind , input , } } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) { match self { HfPlusLeaf :: ForEach { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> for_each (# f) ; }) ; } HfPlusLeaf :: DestSink { sink , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink) ; }) ; } HfPlusLeaf :: CycleSink { ident , location_kind , input , } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; assert_eq ! (input_location_id , * location_id , "cycle_sink location mismatch") ; graph_builders . entry (* location_id) . or_default () . add_statement (parse_quote ! { # ident = # input_ident ; }) ; } } } } pub use crate :: ir :: HfPlusNode ; pub type SeenTees < 'a > = HashMap < * const RefCell < HfPlusNode < 'a > > , Rc < RefCell < HfPlusNode < 'a > > > > ; # [cfg (stageleft_macro)] impl < 'a > HfPlusNode < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (& mut self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) { self . transform_children (| n , s | n . compile_network :: < D > (compile_env , s , nodes , clusters) , seen_tees ,) ; if let HfPlusNode :: Network { from_location , to_location , instantiate_fn , .. } = self { let (sink_expr , source_expr , connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { let ((sink , source) , connect_fn) = match (from_location , to_location) { (LocationId :: Process (from) , LocationId :: Process (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: o2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Process (from) , LocationId :: Cluster (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: o2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Process (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: m2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Cluster (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: m2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } } ; (sink , source , connect_fn) } DebugInstantiate :: Finalized (_ , _ , _) => panic ! ("network already finalized") , } ; * instantiate_fn = DebugInstantiate :: Finalized (sink_expr , source_expr , connect_fn) ; } } pub fn connect_network (& mut self , seen_tees : & mut SeenTees < 'a >) { self . transform_children (| n , s | n . connect_network (s) , seen_tees) ; if let HfPlusNode :: Network { instantiate_fn , .. } = self { match instantiate_fn { DebugInstantiate :: Building () => panic ! ("network not built") , DebugInstantiate :: Finalized (_ , _ , ref connect_fn) => { connect_fn () ; } } } } pub fn transform_children (& mut self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) { match self { HfPlusNode :: Placeholder => { panic ! () ; } HfPlusNode :: Source { .. } => { } HfPlusNode :: CycleSource { .. } => { } HfPlusNode :: Tee { inner } => { if let Some (transformed) = seen_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { * inner = transformed . clone () ; } else { let transformed_cell = Rc :: new (RefCell :: new (HfPlusNode :: Placeholder)) ; seen_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , transformed_cell . clone () ,) ; let mut orig = inner . replace (HfPlusNode :: Placeholder) ; transform (& mut orig , seen_tees) ; * transformed_cell . borrow_mut () = orig ; * inner = transformed_cell ; } } HfPlusNode :: Persist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Unpersist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Delta (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Union (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossProduct (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossSingleton (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Join (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Difference (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: AntiJoin (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Map { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FlatMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Filter { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FilterMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Sort (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: DeferTick (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Enumerate (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Inspect { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Unique (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Fold { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FoldKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Reduce { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: ReduceKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Network { input , .. } => { transform (input . as_mut () , seen_tees) ; } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) -> (syn :: Ident , usize) { match self { HfPlusNode :: Placeholder => { panic ! () } HfPlusNode :: Persist (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let persist_id = * next_stmt_id ; * next_stmt_id += 1 ; let persist_ident = syn :: Ident :: new (& format ! ("stream_{}" , persist_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # persist_ident = # inner_ident -> persist ::<'static > () ; }) ; (persist_ident , location) } HfPlusNode :: Unpersist (_) => { panic ! ("Unpersist is a marker node and should have been optimized away. This is likely a compiler bug.") } HfPlusNode :: Delta (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let delta_id = * next_stmt_id ; * next_stmt_id += 1 ; let delta_ident = syn :: Ident :: new (& format ! ("stream_{}" , delta_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # delta_ident = # inner_ident -> multiset_delta () ; }) ; (delta_ident , location) } HfPlusNode :: Source { source , location_kind , } => { let source_id = * next_stmt_id ; * next_stmt_id += 1 ; let source_ident = syn :: Ident :: new (& format ! ("stream_{}" , source_id) , Span :: call_site ()) ; let source_stmt = match source { HfPlusSource :: Stream (expr) => { parse_quote ! { # source_ident = source_stream (# expr) ; } } HfPlusSource :: Iter (expr) => { parse_quote ! { # source_ident = source_iter (# expr) ; } } HfPlusSource :: Interval (expr) => { parse_quote ! { # source_ident = source_interval (# expr) ; } } HfPlusSource :: Spin () => { parse_quote ! { # source_ident = spin () ; } } } ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; graph_builders . entry (* location_id) . or_default () . add_statement (source_stmt) ; (source_ident , * location_id) } HfPlusNode :: CycleSource { ident , location_kind , } => { let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; (ident . clone () , * location_id) } HfPlusNode :: Tee { inner } => { if let Some (ret) = built_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { ret . clone () } else { let (inner_ident , inner_location_id) = inner . borrow () . emit (graph_builders , built_tees , next_stmt_id) ; let tee_id = * next_stmt_id ; * next_stmt_id += 1 ; let tee_ident = syn :: Ident :: new (& format ! ("stream_{}" , tee_id) , Span :: call_site ()) ; let builder = graph_builders . entry (inner_location_id) . or_default () ; builder . add_statement (parse_quote ! { # tee_ident = # inner_ident -> tee () ; }) ; built_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , (tee_ident . clone () , inner_location_id) ,) ; (tee_ident , inner_location_id) } } HfPlusNode :: Union (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "union inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let union_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # union_ident = union () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [0] # union_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # union_ident ; }) ; (union_ident , left_location_id) } HfPlusNode :: CrossSingleton (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "cross_singleton inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let cross_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # cross_ident = cross_singleton () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [input] # cross_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [single] # cross_ident ; }) ; (cross_ident , left_location_id) } HfPlusNode :: CrossProduct (..) | HfPlusNode :: Join (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: CrossProduct (..)) { parse_quote ! (cross_join_multiset) } else { parse_quote ! (join_multiset) } ; let (HfPlusNode :: CrossProduct (left , right) | HfPlusNode :: Join (left , right)) = self else { unreachable ! () } ; let (left_inner , left_was_persist) = if let HfPlusNode :: Persist (left) = left . as_ref () { (left , true) } else { (left , false) } ; let (right_inner , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left_inner . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right_inner . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "join / cross product inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; match (left_was_persist , right_was_persist) { (true , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'static > () ; }) ; } (true , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'tick > () ; }) ; } (false , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } (false , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } } ; builder . add_statement (parse_quote ! { # left_ident -> [0] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Difference (..) | HfPlusNode :: AntiJoin (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Difference (..)) { parse_quote ! (difference_multiset) } else { parse_quote ! (anti_join_multiset) } ; let (HfPlusNode :: Difference (left , right) | HfPlusNode :: AntiJoin (left , right)) = self else { unreachable ! () } ; let (right , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "difference / anti join inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; if right_was_persist { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } else { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } builder . add_statement (parse_quote ! { # left_ident -> [pos] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [neg] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Map { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let map_id = * next_stmt_id ; * next_stmt_id += 1 ; let map_ident = syn :: Ident :: new (& format ! ("stream_{}" , map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # map_ident = # input_ident -> map (# f) ; }) ; (map_ident , input_location_id) } HfPlusNode :: FlatMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let flat_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let flat_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , flat_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # flat_map_ident = # input_ident -> flat_map (# f) ; }) ; (flat_map_ident , input_location_id) } HfPlusNode :: Filter { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_ident = # input_ident -> filter (# f) ; }) ; (filter_ident , input_location_id) } HfPlusNode :: FilterMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_map_ident = # input_ident -> filter_map (# f) ; }) ; (filter_map_ident , input_location_id) } HfPlusNode :: Sort (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sort_id = * next_stmt_id ; * next_stmt_id += 1 ; let sort_ident = syn :: Ident :: new (& format ! ("stream_{}" , sort_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # sort_ident = # input_ident -> sort () ; }) ; (sort_ident , input_location_id) } HfPlusNode :: DeferTick (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let defer_tick_id = * next_stmt_id ; * next_stmt_id += 1 ; let defer_tick_ident = syn :: Ident :: new (& format ! ("stream_{}" , defer_tick_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # defer_tick_ident = # input_ident -> defer_tick_lazy () ; }) ; (defer_tick_ident , input_location_id) } HfPlusNode :: Enumerate (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let enumerate_id = * next_stmt_id ; * next_stmt_id += 1 ; let enumerate_ident = syn :: Ident :: new (& format ! ("stream_{}" , enumerate_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # enumerate_ident = # input_ident -> enumerate () ; }) ; (enumerate_ident , input_location_id) } HfPlusNode :: Inspect { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let inspect_id = * next_stmt_id ; * next_stmt_id += 1 ; let inspect_ident = syn :: Ident :: new (& format ! ("stream_{}" , inspect_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # inspect_ident = # input_ident -> inspect (# f) ; }) ; (inspect_ident , input_location_id) } HfPlusNode :: Unique (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let unique_id = * next_stmt_id ; * next_stmt_id += 1 ; let unique_ident = syn :: Ident :: new (& format ! ("stream_{}" , unique_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # unique_ident = # input_ident -> unique ::<'tick > () ; }) ; (unique_ident , input_location_id) } HfPlusNode :: Fold { .. } | HfPlusNode :: FoldKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Fold { .. }) { parse_quote ! (fold) } else { parse_quote ! (fold_keyed) } ; let (HfPlusNode :: Fold { init , acc , input } | HfPlusNode :: FoldKeyed { init , acc , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let fold_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'static > (# init , # acc) ; }) ; } else { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'tick > (# init , # acc) ; }) ; } (fold_ident , input_location_id) } HfPlusNode :: Reduce { .. } | HfPlusNode :: ReduceKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Reduce { .. }) { parse_quote ! (reduce) } else { parse_quote ! (reduce_keyed) } ; let (HfPlusNode :: Reduce { f , input } | HfPlusNode :: ReduceKeyed { f , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let reduce_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'static > (# f) ; }) ; } else { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'tick > (# f) ; }) ; } (reduce_ident , input_location_id) } HfPlusNode :: Network { from_location : _ , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input , } => { let (sink_expr , source_expr , _connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { panic ! ("Expected the network to be finalized") } DebugInstantiate :: Finalized (sink , source , connect_fn) => { (sink , source , connect_fn) } } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sender_builder = graph_builders . entry (input_location_id) . or_default () ; if let Some (serialize_pipeline) = serialize_pipeline { sender_builder . add_statement (parse_quote ! { # input_ident -> # serialize_pipeline -> dest_sink (# sink_expr) ; }) ; } else { sender_builder . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink_expr) ; }) ; } let to_id = match to_location { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let receiver_builder = graph_builders . entry (* to_id) . or_default () ; let receiver_stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let receiver_stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , receiver_stream_id) , Span :: call_site ()) ; if let Some (deserialize_pipeline) = deserialize_pipeline { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) -> # deserialize_pipeline ; }) ; } else { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) ; }) ; } (receiver_stream_ident , * to_id) } } } } } pub mod persist_pullup { pub use std :: cell :: RefCell ; pub use std :: collections :: HashSet ; pub use std :: ops :: Deref ; pub use crate :: ir :: * ; pub fn persist_pullup_node < 'a > (node : & mut HfPlusNode < 'a > , seen_tees : & mut SeenTees < 'a > , persist_pulled_tees : & mut HashSet < * const RefCell < HfPlusNode < 'a > > > ,) { node . transform_children (| n , s | persist_pullup_node (n , s , persist_pulled_tees) , seen_tees ,) ; match node { HfPlusNode :: Unpersist (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Unpersist (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Delta (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Delta (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Tee { inner } => { if persist_pulled_tees . contains (& (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >)) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } else { let inner_borrow = inner . borrow () ; if let HfPlusNode :: Persist (_) = inner_borrow . deref () { drop (inner_borrow) ; persist_pulled_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >) ; if let HfPlusNode :: Persist (box behind_persist) = inner . replace (HfPlusNode :: Placeholder) { * inner . borrow_mut () = behind_persist ; } else { unreachable ! () } * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } } } HfPlusNode :: Map { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Map { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Map { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: FlatMap { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: FlatMap { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: FlatMap { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Filter { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Filter { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Filter { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Network { input : box HfPlusNode :: Persist (_) , .. } => { if let HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Union (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Union (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Union (left , right))) ; } else { unreachable ! () } } HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: CrossProduct (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,) ,)))) ; } else { unreachable ! () } } HfPlusNode :: Join (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Join (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: Join (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,))))) ; } else { unreachable ! () } } _ => { } } } pub fn persist_pullup (ir : Vec < HfPlusLeaf >) -> Vec < HfPlusLeaf > { let mut seen_tees = Default :: default () ; let mut persist_pulled_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| n , s | persist_pullup_node (n , s , & mut persist_pulled_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn persist_pullup_through_map () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } # [test] fn persist_pullup_behind_tee () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; let before_tee = flow . source_iter (& process , q ! (0 .. 10)) . tick_batch () . persist () ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } } } pub mod profiler { pub use std :: cell :: RefCell ; pub use hydroflow :: futures :: channel :: mpsc :: UnboundedSender ; pub use stageleft :: * ; pub use crate as hydroflow_plus ; pub use crate :: ir :: * ; pub use crate :: RuntimeContext ; pub fn increment_counter (count : & mut u64) { * count += 1 ; } pub fn quoted_any_fn < 'a , F : Fn (& usize) + 'a , Q : IntoQuotedMut < 'a , F > > (q : Q) -> Q { q } # [doc = " Add a profiling node before each node to count the cardinality of its input"] pub fn add_profiling_node < 'a > (node : & mut HfPlusNode < 'a > , _context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > , id : & mut u32 , seen_tees : & mut SeenTees < 'a > ,) { let my_id = * id ; * id += 1 ; node . transform_children (| node , seen_tees | { add_profiling_node (node , _context , counters , counter_queue , id , seen_tees) } , seen_tees ,) ; let orig_node = std :: mem :: replace (node , HfPlusNode :: Placeholder) ; * node = HfPlusNode :: Inspect { f : quoted_any_fn (q ! ({ counter_queue . borrow () . unbounded_send ((my_id as usize , counters . borrow () [my_id as usize])) . unwrap () ; counters . borrow_mut () [my_id as usize] = 0 ; move | _ | { hydroflow_plus :: profiler :: increment_counter (& mut counters . borrow_mut () [my_id as usize] ,) ; } })) . splice () . into () , input : Box :: new (orig_node) , } } # [doc = " Count the cardinality of each input and periodically output to a file"] pub fn profiling < 'a > (ir : Vec < HfPlusLeaf < 'a > > , context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > ,) -> Vec < HfPlusLeaf < 'a > > { let mut id = 0 ; let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | { add_profiling_node (node , context , counters , counter_queue , & mut id , seen_tees) } , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn profiler_wrapping_all_operators () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let runtime_context = flow . runtime_context () ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (& built . ir ()) ; let counters = RuntimeData :: new ("Fake") ; let counter_queue = RuntimeData :: new ("Fake") ; let pushed_down = built . with_default_optimize () . optimize_with (| ir | super :: profiling (ir , runtime_context , counters , counter_queue)) ; insta :: assert_debug_snapshot ! (& pushed_down . ir ()) ; let _ = pushed_down . compile_no_network :: < MultiGraph > () ; } } } pub mod properties { pub use std :: collections :: HashSet ; pub use stageleft :: * ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , SeenTees } ; pub use crate :: properties :: PropertyDatabase ; # [doc = " Allows us to convert the hydroflow datatype for folds to a binary operation for the algebra"] # [doc = " property tests."] # [allow (dead_code)] pub fn convert_hf_to_binary < I , A : Default , F : Fn (& mut A , I) > (f : F) -> impl Fn (I , I) -> A { move | a , b | { let mut acc = Default :: default () ; f (& mut acc , a) ; f (& mut acc , b) ; acc } } # [cfg (stageleft_macro)] impl PropertyDatabase { # [doc = " Tags the expression as commutative."] pub fn add_commutative_tag < 'a , I , A , F : Fn (& mut A , I) , Q : Quoted < 'a , F > + Clone > (& mut self , expr : Q ,) -> Q { let expr_clone = expr . clone () ; self . commutative . insert (expr_clone . splice ()) ; expr } pub fn is_tagged_commutative (& self , expr : & syn :: Expr) -> bool { self . commutative . contains (expr) } } pub fn properties_optimize_node < 'a > (node : & mut HfPlusNode < 'a > , db : & PropertyDatabase , seen_tees : & mut SeenTees < 'a > ,) { node . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , seen_tees ,) ; match node { HfPlusNode :: ReduceKeyed { f , .. } if db . is_tagged_commutative (& f . 0) => { dbg ! ("IDENTIFIED COMMUTATIVE OPTIMIZATION for {:?}" , & f) ; } _ => { } } } pub fn properties_optimize < 'a > (ir : Vec < HfPlusLeaf < 'a > > , db : & PropertyDatabase ,) -> Vec < HfPlusLeaf < 'a > > { let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use super :: * ; use crate :: deploy :: SingleProcessGraph ; use crate :: FlowBuilder ; # [test] fn test_property_database () { let mut db = PropertyDatabase :: default () ; assert ! (! db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; let _ = db . add_commutative_tag (q ! (| a : & mut i32 , b : i32 | * a += b)) ; assert ! (db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; } # [test] fn test_property_optimized () { let flow = FlowBuilder :: new () ; let mut database = PropertyDatabase :: default () ; let process = flow . process :: < () > () ; let counter_func = q ! (| count : & mut i32 , _ | * count += 1) ; let _ = database . add_commutative_tag (counter_func) ; flow . source_iter (& process , q ! (vec ! [])) . map (q ! (| string : String | (string , ()))) . tick_batch () . fold_keyed (q ! (|| 0) , counter_func) . all_ticks () . for_each (q ! (| (string , count) | println ! ("{}: {}" , string , count))) ; let built = flow . finalize () . optimize_with (| ir | properties_optimize (ir , & database)) . with_default_optimize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let _ = built . compile_no_network :: < SingleProcessGraph > () ; } } } pub use crate :: RuntimeContext ; # [cfg (stageleft_macro)] impl Copy for RuntimeContext < '_ > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Context > for RuntimeContext < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (quote ! (& context))) } } pub use crate :: HfCompiled ; # [cfg (stageleft_macro)] impl < 'a , ID > HfCompiled < 'a , ID > { pub fn hydroflow_ir (& self) -> & BTreeMap < usize , HydroflowGraph > { & self . hydroflow_ir } } # [cfg (stageleft_macro)] impl < 'a > HfCompiled < 'a , usize > { pub fn with_dynamic_id (self , id : impl Quoted < 'a , usize >) -> HfBuiltWithId < 'a > { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; let mut conditioned_tokens = None ; for (subgraph_id , flat_graph) in self . hydroflow_ir { let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; let my_extra_stmts = self . extra_stmts . get (& subgraph_id) . cloned () . unwrap_or_default () ; if let Some (conditioned_tokens) = conditioned_tokens . as_mut () { * conditioned_tokens = syn :: parse_quote ! { # conditioned_tokens else if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } } ; } else { conditioned_tokens = Some (syn :: parse_quote ! { if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } }) ; } } let conditioned_tokens : TokenStream = conditioned_tokens . unwrap () ; let id = id . splice () ; HfBuiltWithId { tokens : syn :: parse_quote ! ({ let __given_id = # id ; # conditioned_tokens else { panic ! ("Invalid node id: {}" , __given_id) ; } }) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfCompiled < 'a , () > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfCompiled < 'a , () > { fn to_tokens (mut self) -> (Option < TokenStream > , Option < TokenStream >) { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; if self . hydroflow_ir . len () != 1 { panic ! ("Expected exactly one subgraph in the Hydroflow IR") ; } let flat_graph = self . hydroflow_ir . remove (& 0) . unwrap () ; let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; (None , Some (tokens)) } } pub use crate :: HfBuiltWithId ; # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfBuiltWithId < 'a > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfBuiltWithId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (self . tokens)) } }
[INFO] [stdout] 1 + pub use std :: collections :: BTreeMap ; pub use std :: marker :: PhantomData ; pub use hydroflow :: scheduled :: context :: Context ; pub use hydroflow :: scheduled :: graph :: Hydroflow ; pub use hydroflow :: * ; pub use lang :: graph :: { partition_graph , HydroflowGraph } ; pub use proc_macro2 :: TokenStream ; pub use quote :: quote ; pub use stageleft :: runtime_support :: FreeVariable ; pub use stageleft :: Quoted ; pub mod runtime_support { pub use bincode ; } pub mod stream { pub use std :: cell :: RefCell ; pub use std :: hash :: Hash ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow :: bytes :: Bytes ; pub use hydroflow :: futures :: Sink ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: quote ; pub use serde :: de :: DeserializeOwned ; pub use serde :: Serialize ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use syn :: parse_quote ; pub use crate :: builder :: { ClusterIds , FlowLeaves } ; pub use crate :: cycle :: { CycleCollection , CycleComplete } ; pub use crate :: ir :: { DebugInstantiate , HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { CanSend , Location , LocationId } ; pub use crate :: { Cluster , Optional , Singleton } ; pub use crate :: stream :: Unbounded ; pub use crate :: stream :: Bounded ; pub use crate :: stream :: NoTick ; pub use crate :: stream :: Tick ; pub use crate :: stream :: Stream ; # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Stream { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Stream < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Stream { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , C , N > > ,) -> Stream < 'a , (T , O) , W , C , N > where O : Clone , { let other : Optional < 'a , O , Bounded , C , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn cross_product < O > (self , other : Stream < 'a , O , W , C , N >) -> Stream < 'a , (T , O) , W , C , N > where T : Clone , O : Clone , { if self . location_kind != other . location_kind { panic ! ("cross_product must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossProduct (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn union (self , other : Stream < 'a , T , W , C , N >) -> Stream < 'a , T , W , C , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn dest_sink < S : Unpin + Sink < T > + 'a > (self , sink : impl Quoted < 'a , S >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: DestSink { sink : sink . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn first (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } # [doc = " Allow this stream through if the other stream has elements, otherwise the output is empty."] pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } # [doc = " Allow this stream through if the other stream is empty, otherwise the output is empty."] pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn enumerate (self) -> Stream < 'a , (usize , T) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Enumerate (Box :: new (self . ir_node . into_inner ())) ,) } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn sort (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Ord , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Sort (Box :: new (self . ir_node . into_inner ())) ,) } pub fn count (self) -> Singleton < 'a , usize , Bounded , Tick , N > { self . fold (q ! (|| 0usize) , q ! (| count , _ | * count += 1)) } pub fn delta (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } pub fn unique (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Eq + Hash , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unique (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn tick_batch (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_prefix (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { self . tick_batch () . persist () } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn for_each < F : Fn (T) + 'a > (self , f : impl IntoQuotedMut < 'a , F >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: ForEach { input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , f : f . splice () . into () , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Unbounded , NoTick , N > { pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . tick_batch () . continue_if (samples . first ()) . all_ticks () } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Unbounded , NoTick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , C , N : Location > Stream < 'a , T , Bounded , C , N > { pub fn filter_not_in (self , other : Stream < 'a , T , Bounded , C , N >) -> Stream < 'a , T , Bounded , C , N > where T : Eq + Hash , { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Difference (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Stream < 'a , & T , W , C , N > { pub fn cloned (self) -> Stream < 'a , T , W , C , N > { self . map (q ! (| d | d . clone ())) } } # [cfg (stageleft_macro)] impl < 'a , K , V1 , W , C , N : Location > Stream < 'a , (K , V1) , W , C , N > { pub fn join < W2 , V2 > (self , n : Stream < 'a , (K , V2) , W2 , C , N > ,) -> Stream < 'a , (K , (V1 , V2)) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Join (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } pub fn anti_join < W2 > (self , n : Stream < 'a , K , W2 , C , N >) -> Stream < 'a , (K , V1) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("anti_join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: AntiJoin (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , K : Eq + Hash , V , N : Location > Stream < 'a , (K , V) , Bounded , Tick , N > { pub fn fold_keyed < A , I : Fn () -> A + 'a , F : Fn (& mut A , V) + 'a > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , A) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FoldKeyed { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce_keyed < F : Fn (& mut V , V) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , V) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: ReduceKeyed { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } pub fn get_this_crate () -> TokenStream { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , Span :: call_site ()) ; quote ! { # ident } } } } pub fn serialize_bincode < T : Serialize > (is_demux : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if is_demux { parse_quote ! { map (| (id , data) | { (id , # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into ()) }) } } else { parse_quote ! { map (| data | { # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into () }) } } } pub fn deserialize_bincode < T : DeserializeOwned > (tagged : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if tagged { parse_quote ! { map (| res | { let (id , b) = res . unwrap () ; (id , # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& b) . unwrap ()) }) } } else { parse_quote ! { map (| res | { # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& res . unwrap ()) . unwrap () }) } } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn send_bincode < N2 : Location , CoreType > (self , other : & N2 ,) -> Stream < 'a , N :: Out < CoreType > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T > , CoreType : Serialize + DeserializeOwned , { let serialize_pipeline = Some (serialize_bincode :: < CoreType > (N :: is_demux ())) ; let deserialize_pipeline = Some (deserialize_bincode :: < CoreType > (N :: is_tagged ())) ; Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bytes < N2 : Location > (self , other : & N2 ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T > , { Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline : None , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline : if N :: is_tagged () { Some (parse_quote ! (map (| (id , b) | (id , b . unwrap () . freeze ())))) } else { Some (parse_quote ! (map (| b | b . unwrap () . freeze ()))) } , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bincode_interleaved < N2 : Location , Tag , CoreType > (self , other : & N2 ,) -> Stream < 'a , CoreType , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T , Out < CoreType > = (Tag , CoreType) > , CoreType : Serialize + DeserializeOwned , { self . send_bincode :: < N2 , CoreType > (other) . map (q ! (| (_ , b) | b)) } pub fn send_bytes_interleaved < N2 : Location , Tag > (self , other : & N2 ,) -> Stream < 'a , Bytes , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T , Out < Bytes > = (Tag , Bytes) > , { self . send_bytes :: < N2 > (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bincode < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < T > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) > , T : Clone + Serialize + DeserializeOwned , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bincode (other) } pub fn broadcast_bincode_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , T , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) , Out < T > = (Tag , T) > + 'a , T : Clone + Serialize + DeserializeOwned , { self . broadcast_bincode (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bytes < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) > + 'a , T : Clone , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bytes (other) } pub fn broadcast_bytes_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , Bytes , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) , Out < Bytes > = (Tag , Bytes) > + 'a , T : Clone , { self . broadcast_bytes (other) . map (q ! (| (_ , b) | b)) } } } pub use stream :: { Bounded , NoTick , Stream , Tick , Unbounded } ; pub mod singleton { pub use std :: cell :: RefCell ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use crate :: builder :: FlowLeaves ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial , CycleComplete } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: Stream ; pub use crate :: singleton :: CrossResult ; # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Singleton < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Singleton :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } pub use crate :: singleton :: Singleton ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Singleton { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleComplete < 'a > for Singleton < 'a , T , Bounded , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleCollectionWithInitial < 'a > for Singleton < 'a , T , Bounded , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , initial : Self , l : LocationId ,) -> Self { Singleton :: new (l , ir_leaves , HfPlusNode :: Union (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , }) , initial . ir_node . into_inner () . into () ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Singleton < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Singleton { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , U , W , C , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (Self :: other_ir_node (other)) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Singleton < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CrossSingleton (Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , Box :: new (HfPlusNode :: Unpersist (Box :: new (Self :: other_ir_node (other)))) ,))) ,) } } pub use crate :: singleton :: Optional ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Optional { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } pub fn some (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: new (singleton . location_kind , singleton . ir_leaves , singleton . ir_node . into_inner () ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > From < Singleton < 'a , T , W , C , N > > for Optional < 'a , T , W , C , N > { fn from (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: some (singleton) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Optional < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Optional { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn into_stream (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , Tick , N > > ,) -> Optional < 'a , (T , O) , Bounded , Tick , N > where O : Clone , { let other : Optional < 'a , O , Bounded , Tick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn union (self , other : Optional < 'a , T , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Optional < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_samples (self) -> Stream < 'a , T , Unbounded , NoTick , N > { self . latest_tick () . all_ticks () } pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . latest_tick () . continue_if (samples . first ()) . latest () . tick_samples () } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Unbounded , NoTick , N > > ,) -> Optional < 'a , (T , O) , Unbounded , NoTick , N > where O : Clone , { let other : Optional < 'a , O , Unbounded , NoTick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } self . latest_tick () . cross_singleton (other . latest_tick ()) . latest () } } } pub use singleton :: { Optional , Singleton } ; pub mod location { pub use std :: marker :: PhantomData ; pub use crate :: location :: LocationId ; pub use crate :: location :: Location ; pub use crate :: location :: Process ; # [cfg (stageleft_macro)] impl < P > Clone for Process < P > { fn clone (& self) -> Self { Process { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < P > Location for Process < P > { fn id (& self) -> LocationId { LocationId :: Process (self . id) } } pub use crate :: location :: Cluster ; # [cfg (stageleft_macro)] impl < C > Clone for Cluster < C > { fn clone (& self) -> Self { Cluster { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < C > Location for Cluster < C > { fn id (& self) -> LocationId { LocationId :: Cluster (self . id) } } pub use crate :: location :: CanSend ; # [cfg (stageleft_macro)] impl < P1 , P2 > CanSend < Process < P2 > > for Process < P1 > { type In < T > = T ; type Out < T > = T ; fn is_demux () -> bool { false } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < P1 , C2 > CanSend < Cluster < C2 > > for Process < P1 > { type In < T > = (u32 , T) ; type Out < T > = T ; fn is_demux () -> bool { true } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < C1 , P2 > CanSend < Process < P2 > > for Cluster < C1 > { type In < T > = T ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { false } fn is_tagged () -> bool { true } } # [cfg (stageleft_macro)] impl < C1 , C2 > CanSend < Cluster < C2 > > for Cluster < C1 > { type In < T > = (u32 , T) ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { true } fn is_tagged () -> bool { true } } } pub use location :: { Cluster , Process } ; pub mod deploy { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use stageleft :: Quoted ; pub mod graphs { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use super :: { LocalDeploy , Node , ProcessSpec } ; pub use crate :: deploy :: graphs :: SingleProcessGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for SingleProcessGraph { type Process = SingleNode ; type Cluster = SingleNode ; type Meta = () ; type GraphId = () ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { SingleNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { SingleNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , SingleProcessGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> SingleNode { SingleNode { } } } pub use crate :: deploy :: graphs :: SingleNode ; # [cfg (stageleft_macro)] impl Node for SingleNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } pub use crate :: deploy :: graphs :: MultiGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for MultiGraph { type Process = MultiNode ; type Cluster = MultiNode ; type Meta = () ; type GraphId = usize ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { MultiNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { MultiNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , MultiGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> MultiNode { MultiNode { } } } pub use crate :: deploy :: graphs :: MultiNode ; # [cfg (stageleft_macro)] impl Node for MultiNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } } pub use graphs :: * ; pub use crate :: deploy :: LocalDeploy ; pub use crate :: deploy :: Deploy ; # [cfg (stageleft_macro)] impl < 'a , T : Deploy < 'a , Process = N , Cluster = C , Meta = M , GraphId = R > , N : Node < Meta = M > , C : Node < Meta = M > , M : Default , R , > LocalDeploy < 'a > for T { type Process = N ; type Cluster = C ; type Meta = M ; type GraphId = R ; fn has_trivial_node () -> bool { < T as Deploy < 'a > > :: has_trivial_node () } fn trivial_process (id : usize) -> Self :: Process { < T as Deploy < 'a > > :: trivial_process (id) } fn trivial_cluster (id : usize) -> Self :: Cluster { < T as Deploy < 'a > > :: trivail_cluster (id) } } pub use crate :: deploy :: ProcessSpec ; pub use crate :: deploy :: ClusterSpec ; pub use crate :: deploy :: Node ; } pub use deploy :: { ClusterSpec , Deploy , ProcessSpec } ; pub mod cycle { pub use std :: marker :: PhantomData ; pub use crate :: builder :: FlowLeaves ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: cycle :: CycleComplete ; pub use crate :: cycle :: CycleCollection ; pub use crate :: cycle :: CycleCollectionWithInitial ; pub use crate :: cycle :: HfCycle ; # [cfg (stageleft_macro)] impl < 'a , S : CycleComplete < 'a > > HfCycle < 'a , S > { pub fn complete (self , stream : S) { let ident = self . ident ; S :: complete (stream , ident) } } } pub use cycle :: HfCycle ; pub mod builder { pub use std :: cell :: RefCell ; pub use std :: collections :: HashMap ; pub use std :: marker :: PhantomData ; pub use std :: rc :: Rc ; pub use std :: time :: Duration ; pub use hydroflow :: futures :: stream :: Stream as FuturesStream ; pub use hydroflow :: { tokio , tokio_stream } ; pub use internal :: TokenStream ; pub use proc_macro2 :: Span ; pub use quote :: quote ; pub use runtime_support :: FreeVariable ; pub use stageleft :: * ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Cluster , Location , LocationId , Process } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: { HfCycle , Optional , RuntimeContext , Singleton , Stream } ; pub mod built { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use hydroflow_lang :: graph :: { eliminate_extra_unions_tees , HydroflowGraph } ; pub use super :: deploy :: { DeployFlow , DeployResult } ; pub use crate :: deploy :: { ClusterSpec , Deploy , LocalDeploy , ProcessSpec } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Cluster , Process } ; pub use crate :: HfCompiled ; pub use crate :: builder :: built :: BuiltFlow ; # [cfg (stageleft_macro)] impl < 'a > Drop for BuiltFlow < 'a > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped BuiltFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn ir (& self) -> & Vec < HfPlusLeaf < 'a > > { & self . ir } pub fn optimize_with (mut self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> BuiltFlow < 'a > { self . used = true ; BuiltFlow { ir : f (std :: mem :: take (& mut self . ir)) , processes : std :: mem :: take (& mut self . processes) , clusters : std :: mem :: take (& mut self . clusters) , used : false , _phantom : PhantomData , } } } pub fn build_inner (ir : & mut Vec < HfPlusLeaf >) -> BTreeMap < usize , HydroflowGraph > { let mut builders = BTreeMap :: new () ; let mut built_tees = HashMap :: new () ; let mut next_stmt_id = 0 ; for leaf in ir { leaf . emit (& mut builders , & mut built_tees , & mut next_stmt_id) ; } builders . into_iter () . map (| (k , v) | { let (mut flat_graph , _ , _) = v . build () ; eliminate_extra_unions_tees (& mut flat_graph) ; (k , flat_graph) }) . collect () } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn compile_no_network < D : LocalDeploy < 'a > > (mut self) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; HfCompiled { hydroflow_ir : build_inner (& mut self . ir) , extra_stmts : BTreeMap :: new () , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> BuiltFlow < 'a > { self . optimize_with (crate :: persist_pullup :: persist_pullup) } fn into_deploy < D : LocalDeploy < 'a > > (mut self) -> DeployFlow < 'a , D > { self . used = true ; let processes = if D :: has_trivial_node () { self . processes . iter () . map (| id | (* id , D :: trivial_process (* id))) . collect () } else { HashMap :: new () } ; let clusters = if D :: has_trivial_node () { self . clusters . iter () . map (| id | (* id , D :: trivial_cluster (* id))) . collect () } else { HashMap :: new () } ; DeployFlow { ir : std :: mem :: take (& mut self . ir) , nodes : processes , clusters , used : false , _phantom : PhantomData , } } pub fn with_process < P , D : LocalDeploy < 'a > > (self , process : & Process < P > , spec : impl ProcessSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_process (process , spec) } pub fn with_cluster < C , D : LocalDeploy < 'a > > (self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_cluster (cluster , spec) } pub fn compile < D : Deploy < 'a > + 'a > (self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . into_deploy :: < D > () . compile (env) } pub fn deploy < D : Deploy < 'a , CompileEnv = () > + 'a > (self , env : & mut D :: InstantiateEnv ,) -> DeployResult < 'a , D > { self . into_deploy :: < D > () . deploy (env) } } } pub mod deploy { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use proc_macro2 :: Span ; pub use stageleft :: Quoted ; pub use super :: built :: build_inner ; pub use crate :: deploy :: { LocalDeploy , Node } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: { Cluster , ClusterSpec , Deploy , HfCompiled , Process , ProcessSpec } ; pub use crate :: builder :: deploy :: DeployFlow ; # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > Drop for DeployFlow < 'a , D > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped DeployFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > DeployFlow < 'a , D > { pub fn with_process < P > (mut self , process : & Process < P > , spec : impl ProcessSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < P > () . to_string () ; self . nodes . insert (process . id , spec . build (process . id , & tag_name)) ; self } pub fn with_cluster < C > (mut self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < C > () . to_string () ; self . clusters . insert (cluster . id , spec . build (cluster . id , & tag_name)) ; self } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployFlow < 'a , D > { pub fn compile (mut self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; let mut seen_tees : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | leaf . compile_network :: < D > (env , & mut seen_tees , & self . nodes , & self . clusters)) . collect () ; let extra_stmts = self . extra_stmts (env) ; HfCompiled { hydroflow_ir : build_inner (& mut ir_leaves_networked) , extra_stmts , _phantom : PhantomData , } } fn extra_stmts (& self , env : & < D as Deploy < 'a > > :: CompileEnv) -> BTreeMap < usize , Vec < syn :: Stmt > > { let all_locations_count = self . nodes . len () + self . clusters . len () ; let mut extra_stmts : BTreeMap < usize , Vec < syn :: Stmt > > = BTreeMap :: new () ; for & c_id in self . clusters . keys () { let self_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , c_id) , Span :: call_site () ,) ; let self_id_expr = D :: cluster_self_id (env) . splice () ; extra_stmts . entry (c_id) . or_default () . push (syn :: parse_quote ! { let # self_id_ident = # self_id_expr ; }) ; for other_location in 0 .. all_locations_count { let other_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , c_id) , Span :: call_site () ,) ; let other_id_expr = D :: cluster_ids (env , c_id) . splice () ; extra_stmts . entry (other_location) . or_default () . push (syn :: parse_quote ! { let # other_id_ident = # other_id_expr ; }) ; } } extra_stmts } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a , CompileEnv = () > > DeployFlow < 'a , D > { # [must_use] pub fn deploy (mut self , env : & mut D :: InstantiateEnv) -> DeployResult < 'a , D > { self . used = true ; let mut seen_tees_instantiate : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | { leaf . compile_network :: < D > (& () , & mut seen_tees_instantiate , & self . nodes , & self . clusters ,) }) . collect () ; let mut compiled = build_inner (& mut ir_leaves_networked) ; let mut extra_stmts = self . extra_stmts (& ()) ; let mut meta = D :: Meta :: default () ; let (mut processes , mut clusters) = (std :: mem :: take (& mut self . nodes) . into_iter () . map (| (node_id , node) | { node . instantiate (env , & mut meta , compiled . remove (& node_id) . unwrap () , extra_stmts . remove (& node_id) . unwrap_or_default () ,) ; (node_id , node) }) . collect :: < HashMap < _ , _ > > () , std :: mem :: take (& mut self . clusters) . into_iter () . map (| (cluster_id , cluster) | { cluster . instantiate (env , & mut meta , compiled . remove (& cluster_id) . unwrap () , extra_stmts . remove (& cluster_id) . unwrap_or_default () ,) ; (cluster_id , cluster) }) . collect :: < HashMap < _ , _ > > () ,) ; for node in processes . values_mut () { node . update_meta (& meta) ; } for cluster in clusters . values_mut () { cluster . update_meta (& meta) ; } let mut seen_tees_connect = HashMap :: new () ; for leaf in ir_leaves_networked { leaf . connect_network (& mut seen_tees_connect) ; } DeployResult { processes , clusters , } } } pub use crate :: builder :: deploy :: DeployResult ; # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployResult < 'a , D > { pub fn get_process < P > (& self , p : & Process < P >) -> & D :: Process { let id = match p . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . processes . get (& id) . unwrap () } pub fn get_cluster < C > (& self , c : & Cluster < C >) -> & D :: Cluster { let id = match c . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . clusters . get (& id) . unwrap () } } } # [doc = " Tracks the leaves of the dataflow IR. This is referenced by"] # [doc = " `Stream` and `HfCycle` to build the IR. The inner option will"] # [doc = " be set to `None` when this builder is finalized."] pub type FlowLeaves < 'a > = Rc < RefCell < Option < Vec < HfPlusLeaf < 'a > > > > > ; pub use crate :: builder :: ClusterIds ; # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Vec < u32 > > for ClusterIds < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , & 'a Vec < u32 > > for ClusterIds < 'a > { } # [derive (Copy , Clone)] pub struct ClusterSelfId < 'a > { pub id : usize , pub _phantom : PhantomData < & 'a mut & 'a u32 > , } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < u32 > for ClusterSelfId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , u32 > for ClusterSelfId < 'a > { } pub use crate :: builder :: FlowBuilder ; # [cfg (stageleft_macro)] impl < 'a > Drop for FlowBuilder < 'a > { fn drop (& mut self) { if ! self . finalized { panic ! ("Dropped FlowBuilder without finalizing, you may have forgotten to call `with_default_optimize`, `optimize_with`, or `finalize`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > QuotedContext for FlowBuilder < 'a > { fn create () -> Self { FlowBuilder :: new () } } # [cfg (stageleft_macro)] impl < 'a > FlowBuilder < 'a > { # [allow (clippy :: new_without_default)] pub fn new () -> FlowBuilder < 'a > { FlowBuilder { ir_leaves : Rc :: new (RefCell :: new (Some (Vec :: new ()))) , nodes : RefCell :: new (vec ! []) , clusters : RefCell :: new (vec ! []) , cycle_ids : RefCell :: new (HashMap :: new ()) , next_node_id : RefCell :: new (0) , finalized : false , _phantom : PhantomData , } } pub fn finalize (mut self) -> built :: BuiltFlow < 'a > { self . finalized = true ; built :: BuiltFlow { ir : self . ir_leaves . borrow_mut () . take () . unwrap () , processes : self . nodes . replace (vec ! []) , clusters : self . clusters . replace (vec ! []) , used : false , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> built :: BuiltFlow < 'a > { self . finalize () . with_default_optimize () } pub fn optimize_with (self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> built :: BuiltFlow < 'a > { self . finalize () . optimize_with (f) } pub fn ir_leaves (& self) -> & FlowLeaves < 'a > { & self . ir_leaves } pub fn process < P > (& self) -> Process < P > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . nodes . borrow_mut () . push (id) ; Process { id , _phantom : PhantomData , } } pub fn cluster < C > (& self) -> Cluster < C > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . clusters . borrow_mut () . push (id) ; Cluster { id , _phantom : PhantomData , } } pub fn runtime_context (& self) -> RuntimeContext < 'a > { RuntimeContext { _phantom : PhantomData , } } pub fn cluster_members < C > (& self , cluster : & Cluster < C > ,) -> impl Quoted < 'a , & 'a Vec < u32 > > + Copy + 'a { ClusterIds { id : cluster . id , _phantom : PhantomData , } } pub fn cluster_self_id < C > (& self , cluster : & Cluster < C >) -> impl Quoted < 'a , u32 > + Copy + 'a { ClusterSelfId { id : cluster . id , _phantom : PhantomData , } } pub fn spin < L : Location > (& self , on : & L) -> Stream < 'a , () , Unbounded , NoTick , L > { Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Spin () , location_kind : on . id () , })) ,) } pub fn spin_batch < L : Location > (& self , on : & L , batch_size : impl Quoted < 'a , usize > + Copy + 'a ,) -> Stream < 'a , () , Bounded , Tick , L > { self . spin (on) . flat_map (q ! (move | _ | 0 .. batch_size)) . map (q ! (| _ | ())) . tick_batch () } pub fn source_stream < T , E : FuturesStream < Item = T > + Unpin , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Unbounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Stream (e . into ()) , location_kind : on . id () , })) ,) } pub fn source_iter < T , E : IntoIterator < Item = T > , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Bounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , })) ,) } pub fn singleton < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Singleton < 'a , T , Bounded , NoTick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Singleton :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,)))) ,) } pub fn singleton_first_tick < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Optional < 'a , T , Bounded , Tick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,) } pub fn source_interval < L : Location > (& self , on : & L , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , () , Unbounded , NoTick , L > { let interval = interval . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : on . id () , })) ,) } pub fn source_interval_delayed < L : Location > (& self , on : & L , delay : impl Quoted < 'a , Duration > + Copy + 'a , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , tokio :: time :: Instant , Unbounded , NoTick , L > { self . source_stream (on , q ! (tokio_stream :: wrappers :: IntervalStream :: new (tokio :: time :: interval_at (tokio :: time :: Instant :: now () + delay , interval))) ,) . tick_batch () . first () . latest () } pub fn cycle < S : CycleCollection < 'a > > (& self , on : & S :: Location) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , on . id ()) ,) } pub fn cycle_with_initial < S : CycleCollectionWithInitial < 'a > > (& self , on : & S :: Location , initial : S ,) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , initial , on . id ()) ,) } } } pub use builder :: FlowBuilder ; pub mod ir { pub use core :: panic ; pub use std :: cell :: RefCell ; pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow_lang :: graph :: FlatGraphBuilder ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: ToTokens ; pub use syn :: parse_quote ; pub use crate :: deploy :: Deploy ; pub use crate :: location :: LocationId ; pub use crate :: ir :: DebugExpr ; # [cfg (stageleft_macro)] impl From < syn :: Expr > for DebugExpr { fn from (expr : syn :: Expr) -> DebugExpr { DebugExpr (expr) } } # [cfg (stageleft_macro)] impl Deref for DebugExpr { type Target = syn :: Expr ; fn deref (& self) -> & Self :: Target { & self . 0 } } # [cfg (stageleft_macro)] impl ToTokens for DebugExpr { fn to_tokens (& self , tokens : & mut TokenStream) { self . 0 . to_tokens (tokens) ; } } # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugExpr { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "{}" , self . 0 . to_token_stream ()) } } pub use crate :: ir :: DebugInstantiate ; # [cfg (stageleft_macro)] impl < 'a > std :: fmt :: Debug for DebugInstantiate < 'a > { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<network instantiate>") } } pub use crate :: ir :: DebugPipelineFn ; # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugPipelineFn { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<function>") } } pub use crate :: ir :: HfPlusSource ; pub use crate :: ir :: HfPlusLeaf ; # [cfg (stageleft_macro)] impl < 'a > HfPlusLeaf < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . compile_network :: < D > (compile_env , s , nodes , clusters) ; } , seen_tees ,) } pub fn connect_network (self , seen_tees : & mut SeenTees < 'a >) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . connect_network (s) ; } , seen_tees ,) } pub fn transform_children (self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) -> HfPlusLeaf < 'a > { match self { HfPlusLeaf :: ForEach { f , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: ForEach { f , input } } HfPlusLeaf :: DestSink { sink , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: DestSink { sink , input } } HfPlusLeaf :: CycleSink { ident , location_kind , mut input , } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: CycleSink { ident , location_kind , input , } } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) { match self { HfPlusLeaf :: ForEach { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> for_each (# f) ; }) ; } HfPlusLeaf :: DestSink { sink , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink) ; }) ; } HfPlusLeaf :: CycleSink { ident , location_kind , input , } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; assert_eq ! (input_location_id , * location_id , "cycle_sink location mismatch") ; graph_builders . entry (* location_id) . or_default () . add_statement (parse_quote ! { # ident = # input_ident ; }) ; } } } } pub use crate :: ir :: HfPlusNode ; pub type SeenTees < 'a > = HashMap < * const RefCell < HfPlusNode < 'a > > , Rc < RefCell < HfPlusNode < 'a > > > > ; # [cfg (stageleft_macro)] impl < 'a > HfPlusNode < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (& mut self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) { self . transform_children (| n , s | n . compile_network :: < D > (compile_env , s , nodes , clusters) , seen_tees ,) ; if let HfPlusNode :: Network { from_location , to_location , instantiate_fn , .. } = self { let (sink_expr , source_expr , connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { let ((sink , source) , connect_fn) = match (from_location , to_location) { (LocationId :: Process (from) , LocationId :: Process (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: o2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Process (from) , LocationId :: Cluster (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: o2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Process (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: m2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Cluster (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: m2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } } ; (sink , source , connect_fn) } DebugInstantiate :: Finalized (_ , _ , _) => panic ! ("network already finalized") , } ; * instantiate_fn = DebugInstantiate :: Finalized (sink_expr , source_expr , connect_fn) ; } } pub fn connect_network (& mut self , seen_tees : & mut SeenTees < 'a >) { self . transform_children (| n , s | n . connect_network (s) , seen_tees) ; if let HfPlusNode :: Network { instantiate_fn , .. } = self { match instantiate_fn { DebugInstantiate :: Building () => panic ! ("network not built") , DebugInstantiate :: Finalized (_ , _ , ref connect_fn) => { connect_fn () ; } } } } pub fn transform_children (& mut self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) { match self { HfPlusNode :: Placeholder => { panic ! () ; } HfPlusNode :: Source { .. } => { } HfPlusNode :: CycleSource { .. } => { } HfPlusNode :: Tee { inner } => { if let Some (transformed) = seen_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { * inner = transformed . clone () ; } else { let transformed_cell = Rc :: new (RefCell :: new (HfPlusNode :: Placeholder)) ; seen_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , transformed_cell . clone () ,) ; let mut orig = inner . replace (HfPlusNode :: Placeholder) ; transform (& mut orig , seen_tees) ; * transformed_cell . borrow_mut () = orig ; * inner = transformed_cell ; } } HfPlusNode :: Persist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Unpersist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Delta (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Union (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossProduct (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossSingleton (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Join (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Difference (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: AntiJoin (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Map { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FlatMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Filter { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FilterMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Sort (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: DeferTick (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Enumerate (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Inspect { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Unique (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Fold { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FoldKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Reduce { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: ReduceKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Network { input , .. } => { transform (input . as_mut () , seen_tees) ; } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) -> (syn :: Ident , usize) { match self { HfPlusNode :: Placeholder => { panic ! () } HfPlusNode :: Persist (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let persist_id = * next_stmt_id ; * next_stmt_id += 1 ; let persist_ident = syn :: Ident :: new (& format ! ("stream_{}" , persist_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # persist_ident = # inner_ident -> persist ::<'static > () ; }) ; (persist_ident , location) } HfPlusNode :: Unpersist (_) => { panic ! ("Unpersist is a marker node and should have been optimized away. This is likely a compiler bug.") } HfPlusNode :: Delta (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let delta_id = * next_stmt_id ; * next_stmt_id += 1 ; let delta_ident = syn :: Ident :: new (& format ! ("stream_{}" , delta_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # delta_ident = # inner_ident -> multiset_delta () ; }) ; (delta_ident , location) } HfPlusNode :: Source { source , location_kind , } => { let source_id = * next_stmt_id ; * next_stmt_id += 1 ; let source_ident = syn :: Ident :: new (& format ! ("stream_{}" , source_id) , Span :: call_site ()) ; let source_stmt = match source { HfPlusSource :: Stream (expr) => { parse_quote ! { # source_ident = source_stream (# expr) ; } } HfPlusSource :: Iter (expr) => { parse_quote ! { # source_ident = source_iter (# expr) ; } } HfPlusSource :: Interval (expr) => { parse_quote ! { # source_ident = source_interval (# expr) ; } } HfPlusSource :: Spin () => { parse_quote ! { # source_ident = spin () ; } } } ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; graph_builders . entry (* location_id) . or_default () . add_statement (source_stmt) ; (source_ident , * location_id) } HfPlusNode :: CycleSource { ident , location_kind , } => { let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; (ident . clone () , * location_id) } HfPlusNode :: Tee { inner } => { if let Some (ret) = built_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { ret . clone () } else { let (inner_ident , inner_location_id) = inner . borrow () . emit (graph_builders , built_tees , next_stmt_id) ; let tee_id = * next_stmt_id ; * next_stmt_id += 1 ; let tee_ident = syn :: Ident :: new (& format ! ("stream_{}" , tee_id) , Span :: call_site ()) ; let builder = graph_builders . entry (inner_location_id) . or_default () ; builder . add_statement (parse_quote ! { # tee_ident = # inner_ident -> tee () ; }) ; built_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , (tee_ident . clone () , inner_location_id) ,) ; (tee_ident , inner_location_id) } } HfPlusNode :: Union (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "union inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let union_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # union_ident = union () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [0] # union_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # union_ident ; }) ; (union_ident , left_location_id) } HfPlusNode :: CrossSingleton (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "cross_singleton inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let cross_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # cross_ident = cross_singleton () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [input] # cross_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [single] # cross_ident ; }) ; (cross_ident , left_location_id) } HfPlusNode :: CrossProduct (..) | HfPlusNode :: Join (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: CrossProduct (..)) { parse_quote ! (cross_join_multiset) } else { parse_quote ! (join_multiset) } ; let (HfPlusNode :: CrossProduct (left , right) | HfPlusNode :: Join (left , right)) = self else { unreachable ! () } ; let (left_inner , left_was_persist) = if let HfPlusNode :: Persist (left) = left . as_ref () { (left , true) } else { (left , false) } ; let (right_inner , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left_inner . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right_inner . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "join / cross product inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; match (left_was_persist , right_was_persist) { (true , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'static > () ; }) ; } (true , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'tick > () ; }) ; } (false , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } (false , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } } ; builder . add_statement (parse_quote ! { # left_ident -> [0] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Difference (..) | HfPlusNode :: AntiJoin (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Difference (..)) { parse_quote ! (difference_multiset) } else { parse_quote ! (anti_join_multiset) } ; let (HfPlusNode :: Difference (left , right) | HfPlusNode :: AntiJoin (left , right)) = self else { unreachable ! () } ; let (right , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "difference / anti join inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; if right_was_persist { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } else { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } builder . add_statement (parse_quote ! { # left_ident -> [pos] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [neg] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Map { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let map_id = * next_stmt_id ; * next_stmt_id += 1 ; let map_ident = syn :: Ident :: new (& format ! ("stream_{}" , map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # map_ident = # input_ident -> map (# f) ; }) ; (map_ident , input_location_id) } HfPlusNode :: FlatMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let flat_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let flat_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , flat_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # flat_map_ident = # input_ident -> flat_map (# f) ; }) ; (flat_map_ident , input_location_id) } HfPlusNode :: Filter { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_ident = # input_ident -> filter (# f) ; }) ; (filter_ident , input_location_id) } HfPlusNode :: FilterMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_map_ident = # input_ident -> filter_map (# f) ; }) ; (filter_map_ident , input_location_id) } HfPlusNode :: Sort (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sort_id = * next_stmt_id ; * next_stmt_id += 1 ; let sort_ident = syn :: Ident :: new (& format ! ("stream_{}" , sort_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # sort_ident = # input_ident -> sort () ; }) ; (sort_ident , input_location_id) } HfPlusNode :: DeferTick (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let defer_tick_id = * next_stmt_id ; * next_stmt_id += 1 ; let defer_tick_ident = syn :: Ident :: new (& format ! ("stream_{}" , defer_tick_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # defer_tick_ident = # input_ident -> defer_tick_lazy () ; }) ; (defer_tick_ident , input_location_id) } HfPlusNode :: Enumerate (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let enumerate_id = * next_stmt_id ; * next_stmt_id += 1 ; let enumerate_ident = syn :: Ident :: new (& format ! ("stream_{}" , enumerate_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # enumerate_ident = # input_ident -> enumerate () ; }) ; (enumerate_ident , input_location_id) } HfPlusNode :: Inspect { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let inspect_id = * next_stmt_id ; * next_stmt_id += 1 ; let inspect_ident = syn :: Ident :: new (& format ! ("stream_{}" , inspect_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # inspect_ident = # input_ident -> inspect (# f) ; }) ; (inspect_ident , input_location_id) } HfPlusNode :: Unique (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let unique_id = * next_stmt_id ; * next_stmt_id += 1 ; let unique_ident = syn :: Ident :: new (& format ! ("stream_{}" , unique_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # unique_ident = # input_ident -> unique ::<'tick > () ; }) ; (unique_ident , input_location_id) } HfPlusNode :: Fold { .. } | HfPlusNode :: FoldKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Fold { .. }) { parse_quote ! (fold) } else { parse_quote ! (fold_keyed) } ; let (HfPlusNode :: Fold { init , acc , input } | HfPlusNode :: FoldKeyed { init , acc , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let fold_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'static > (# init , # acc) ; }) ; } else { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'tick > (# init , # acc) ; }) ; } (fold_ident , input_location_id) } HfPlusNode :: Reduce { .. } | HfPlusNode :: ReduceKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Reduce { .. }) { parse_quote ! (reduce) } else { parse_quote ! (reduce_keyed) } ; let (HfPlusNode :: Reduce { f , input } | HfPlusNode :: ReduceKeyed { f , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let reduce_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'static > (# f) ; }) ; } else { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'tick > (# f) ; }) ; } (reduce_ident , input_location_id) } HfPlusNode :: Network { from_location : _ , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input , } => { let (sink_expr , source_expr , _connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { panic ! ("Expected the network to be finalized") } DebugInstantiate :: Finalized (sink , source , connect_fn) => { (sink , source , connect_fn) } } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sender_builder = graph_builders . entry (input_location_id) . or_default () ; if let Some (serialize_pipeline) = serialize_pipeline { sender_builder . add_statement (parse_quote ! { # input_ident -> # serialize_pipeline -> dest_sink (# sink_expr) ; }) ; } else { sender_builder . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink_expr) ; }) ; } let to_id = match to_location { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let receiver_builder = graph_builders . entry (* to_id) . or_default () ; let receiver_stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let receiver_stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , receiver_stream_id) , Span :: call_site ()) ; if let Some (deserialize_pipeline) = deserialize_pipeline { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) -> # deserialize_pipeline ; }) ; } else { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) ; }) ; } (receiver_stream_ident , * to_id) } } } } } pub mod persist_pullup { pub use std :: cell :: RefCell ; pub use std :: collections :: HashSet ; pub use std :: ops :: Deref ; pub use crate :: ir :: * ; pub fn persist_pullup_node < 'a > (node : & mut HfPlusNode < 'a > , seen_tees : & mut SeenTees < 'a > , persist_pulled_tees : & mut HashSet < * const RefCell < HfPlusNode < 'a > > > ,) { node . transform_children (| n , s | persist_pullup_node (n , s , persist_pulled_tees) , seen_tees ,) ; match node { HfPlusNode :: Unpersist (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Unpersist (HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Delta (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Delta (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Tee { inner } => { if persist_pulled_tees . contains (& (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >)) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } else { let inner_borrow = inner . borrow () ; if let HfPlusNode :: Persist (_) = inner_borrow . deref () { drop (inner_borrow) ; persist_pulled_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >) ; if let HfPlusNode :: Persist (box behind_persist) = inner . replace (HfPlusNode :: Placeholder) { * inner . borrow_mut () = behind_persist ; } else { unreachable ! () } * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } } } HfPlusNode :: Map { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Map { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Map { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: FlatMap { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: FlatMap { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: FlatMap { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Filter { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Filter { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Filter { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Network { input : box HfPlusNode :: Persist (_) , .. } => { if let HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Union (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Union (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Union (left , right))) ; } else { unreachable ! () } } HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: CrossProduct (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,) ,)))) ; } else { unreachable ! () } } HfPlusNode :: Join (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Join (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: Join (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,))))) ; } else { unreachable ! () } } _ => { } } } pub fn persist_pullup (ir : Vec < HfPlusLeaf >) -> Vec < HfPlusLeaf > { let mut seen_tees = Default :: default () ; let mut persist_pulled_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| n , s | persist_pullup_node (n , s , & mut persist_pulled_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn persist_pullup_through_map () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } # [test] fn persist_pullup_behind_tee () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; let before_tee = flow . source_iter (& process , q ! (0 .. 10)) . tick_batch () . persist () ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } } } pub mod profiler { pub use std :: cell :: RefCell ; pub use hydroflow :: futures :: channel :: mpsc :: UnboundedSender ; pub use stageleft :: * ; pub use crate as hydroflow_plus ; pub use crate :: ir :: * ; pub use crate :: RuntimeContext ; pub fn increment_counter (count : & mut u64) { * count += 1 ; } pub fn quoted_any_fn < 'a , F : Fn (& usize) + 'a , Q : IntoQuotedMut < 'a , F > > (q : Q) -> Q { q } # [doc = " Add a profiling node before each node to count the cardinality of its input"] pub fn add_profiling_node < 'a > (node : & mut HfPlusNode < 'a > , _context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > , id : & mut u32 , seen_tees : & mut SeenTees < 'a > ,) { let my_id = * id ; * id += 1 ; node . transform_children (| node , seen_tees | { add_profiling_node (node , _context , counters , counter_queue , id , seen_tees) } , seen_tees ,) ; let orig_node = std :: mem :: replace (node , HfPlusNode :: Placeholder) ; * node = HfPlusNode :: Inspect { f : quoted_any_fn (q ! ({ counter_queue . borrow () . unbounded_send ((my_id as usize , counters . borrow () [my_id as usize])) . unwrap () ; counters . borrow_mut () [my_id as usize] = 0 ; move | _ | { hydroflow_plus :: profiler :: increment_counter (& mut counters . borrow_mut () [my_id as usize] ,) ; } })) . splice () . into () , input : Box :: new (orig_node) , } } # [doc = " Count the cardinality of each input and periodically output to a file"] pub fn profiling < 'a > (ir : Vec < HfPlusLeaf < 'a > > , context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > ,) -> Vec < HfPlusLeaf < 'a > > { let mut id = 0 ; let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | { add_profiling_node (node , context , counters , counter_queue , & mut id , seen_tees) } , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn profiler_wrapping_all_operators () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let runtime_context = flow . runtime_context () ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (& built . ir ()) ; let counters = RuntimeData :: new ("Fake") ; let counter_queue = RuntimeData :: new ("Fake") ; let pushed_down = built . with_default_optimize () . optimize_with (| ir | super :: profiling (ir , runtime_context , counters , counter_queue)) ; insta :: assert_debug_snapshot ! (& pushed_down . ir ()) ; let _ = pushed_down . compile_no_network :: < MultiGraph > () ; } } } pub mod properties { pub use std :: collections :: HashSet ; pub use stageleft :: * ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , SeenTees } ; pub use crate :: properties :: PropertyDatabase ; # [doc = " Allows us to convert the hydroflow datatype for folds to a binary operation for the algebra"] # [doc = " property tests."] # [allow (dead_code)] pub fn convert_hf_to_binary < I , A : Default , F : Fn (& mut A , I) > (f : F) -> impl Fn (I , I) -> A { move | a , b | { let mut acc = Default :: default () ; f (& mut acc , a) ; f (& mut acc , b) ; acc } } # [cfg (stageleft_macro)] impl PropertyDatabase { # [doc = " Tags the expression as commutative."] pub fn add_commutative_tag < 'a , I , A , F : Fn (& mut A , I) , Q : Quoted < 'a , F > + Clone > (& mut self , expr : Q ,) -> Q { let expr_clone = expr . clone () ; self . commutative . insert (expr_clone . splice ()) ; expr } pub fn is_tagged_commutative (& self , expr : & syn :: Expr) -> bool { self . commutative . contains (expr) } } pub fn properties_optimize_node < 'a > (node : & mut HfPlusNode < 'a > , db : & PropertyDatabase , seen_tees : & mut SeenTees < 'a > ,) { node . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , seen_tees ,) ; match node { HfPlusNode :: ReduceKeyed { f , .. } if db . is_tagged_commutative (& f . 0) => { dbg ! ("IDENTIFIED COMMUTATIVE OPTIMIZATION for {:?}" , & f) ; } _ => { } } } pub fn properties_optimize < 'a > (ir : Vec < HfPlusLeaf < 'a > > , db : & PropertyDatabase ,) -> Vec < HfPlusLeaf < 'a > > { let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use super :: * ; use crate :: deploy :: SingleProcessGraph ; use crate :: FlowBuilder ; # [test] fn test_property_database () { let mut db = PropertyDatabase :: default () ; assert ! (! db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; let _ = db . add_commutative_tag (q ! (| a : & mut i32 , b : i32 | * a += b)) ; assert ! (db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; } # [test] fn test_property_optimized () { let flow = FlowBuilder :: new () ; let mut database = PropertyDatabase :: default () ; let process = flow . process :: < () > () ; let counter_func = q ! (| count : & mut i32 , _ | * count += 1) ; let _ = database . add_commutative_tag (counter_func) ; flow . source_iter (& process , q ! (vec ! [])) . map (q ! (| string : String | (string , ()))) . tick_batch () . fold_keyed (q ! (|| 0) , counter_func) . all_ticks () . for_each (q ! (| (string , count) | println ! ("{}: {}" , string , count))) ; let built = flow . finalize () . optimize_with (| ir | properties_optimize (ir , & database)) . with_default_optimize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let _ = built . compile_no_network :: < SingleProcessGraph > () ; } } } pub use crate :: RuntimeContext ; # [cfg (stageleft_macro)] impl Copy for RuntimeContext < '_ > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Context > for RuntimeContext < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (quote ! (& context))) } } pub use crate :: HfCompiled ; # [cfg (stageleft_macro)] impl < 'a , ID > HfCompiled < 'a , ID > { pub fn hydroflow_ir (& self) -> & BTreeMap < usize , HydroflowGraph > { & self . hydroflow_ir } } # [cfg (stageleft_macro)] impl < 'a > HfCompiled < 'a , usize > { pub fn with_dynamic_id (self , id : impl Quoted < 'a , usize >) -> HfBuiltWithId < 'a > { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; let mut conditioned_tokens = None ; for (subgraph_id , flat_graph) in self . hydroflow_ir { let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; let my_extra_stmts = self . extra_stmts . get (& subgraph_id) . cloned () . unwrap_or_default () ; if let Some (conditioned_tokens) = conditioned_tokens . as_mut () { * conditioned_tokens = syn :: parse_quote ! { # conditioned_tokens else if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } } ; } else { conditioned_tokens = Some (syn :: parse_quote ! { if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } }) ; } } let conditioned_tokens : TokenStream = conditioned_tokens . unwrap () ; let id = id . splice () ; HfBuiltWithId { tokens : syn :: parse_quote ! ({ let __given_id = # id ; # conditioned_tokens else { panic ! ("Invalid node id: {}" , __given_id) ; } }) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfCompiled < 'a , () > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfCompiled < 'a , () > { fn to_tokens (mut self) -> (Option < TokenStream > , Option < TokenStream >) { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; if self . hydroflow_ir . len () != 1 { panic ! ("Expected exactly one subgraph in the Hydroflow IR") ; } let flat_graph = self . hydroflow_ir . remove (& 0) . unwrap () ; let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; (None , Some (tokens)) } } pub use crate :: HfBuiltWithId ; # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfBuiltWithId < 'a > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfBuiltWithId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (self . tokens)) } }
[INFO] [stdout]   |
[INFO] [stdout] help: ...otherwise replace it with an invocation of macro `deref`
[INFO] [stdout]   |
[INFO] [stdout] 1 - pub use std :: collections :: BTreeMap ; pub use std :: marker :: PhantomData ; pub use hydroflow :: scheduled :: context :: Context ; pub use hydroflow :: scheduled :: graph :: Hydroflow ; pub use hydroflow :: * ; pub use lang :: graph :: { partition_graph , HydroflowGraph } ; pub use proc_macro2 :: TokenStream ; pub use quote :: quote ; pub use stageleft :: runtime_support :: FreeVariable ; pub use stageleft :: Quoted ; pub mod runtime_support { pub use bincode ; } pub mod stream { pub use std :: cell :: RefCell ; pub use std :: hash :: Hash ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow :: bytes :: Bytes ; pub use hydroflow :: futures :: Sink ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: quote ; pub use serde :: de :: DeserializeOwned ; pub use serde :: Serialize ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use syn :: parse_quote ; pub use crate :: builder :: { ClusterIds , FlowLeaves } ; pub use crate :: cycle :: { CycleCollection , CycleComplete } ; pub use crate :: ir :: { DebugInstantiate , HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { CanSend , Location , LocationId } ; pub use crate :: { Cluster , Optional , Singleton } ; pub use crate :: stream :: Unbounded ; pub use crate :: stream :: Bounded ; pub use crate :: stream :: NoTick ; pub use crate :: stream :: Tick ; pub use crate :: stream :: Stream ; # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Stream { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Stream < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Stream { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , C , N > > ,) -> Stream < 'a , (T , O) , W , C , N > where O : Clone , { let other : Optional < 'a , O , Bounded , C , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn cross_product < O > (self , other : Stream < 'a , O , W , C , N >) -> Stream < 'a , (T , O) , W , C , N > where T : Clone , O : Clone , { if self . location_kind != other . location_kind { panic ! ("cross_product must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossProduct (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn union (self , other : Stream < 'a , T , W , C , N >) -> Stream < 'a , T , W , C , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn dest_sink < S : Unpin + Sink < T > + 'a > (self , sink : impl Quoted < 'a , S >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: DestSink { sink : sink . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn first (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } # [doc = " Allow this stream through if the other stream has elements, otherwise the output is empty."] pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } # [doc = " Allow this stream through if the other stream is empty, otherwise the output is empty."] pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn enumerate (self) -> Stream < 'a , (usize , T) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Enumerate (Box :: new (self . ir_node . into_inner ())) ,) } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn sort (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Ord , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Sort (Box :: new (self . ir_node . into_inner ())) ,) } pub fn count (self) -> Singleton < 'a , usize , Bounded , Tick , N > { self . fold (q ! (|| 0usize) , q ! (| count , _ | * count += 1)) } pub fn delta (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } pub fn unique (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Eq + Hash , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unique (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn tick_batch (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_prefix (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { self . tick_batch () . persist () } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn for_each < F : Fn (T) + 'a > (self , f : impl IntoQuotedMut < 'a , F >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: ForEach { input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , f : f . splice () . into () , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Unbounded , NoTick , N > { pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . tick_batch () . continue_if (samples . first ()) . all_ticks () } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Unbounded , NoTick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , C , N : Location > Stream < 'a , T , Bounded , C , N > { pub fn filter_not_in (self , other : Stream < 'a , T , Bounded , C , N >) -> Stream < 'a , T , Bounded , C , N > where T : Eq + Hash , { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Difference (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Stream < 'a , & T , W , C , N > { pub fn cloned (self) -> Stream < 'a , T , W , C , N > { self . map (q ! (| d | d . clone ())) } } # [cfg (stageleft_macro)] impl < 'a , K , V1 , W , C , N : Location > Stream < 'a , (K , V1) , W , C , N > { pub fn join < W2 , V2 > (self , n : Stream < 'a , (K , V2) , W2 , C , N > ,) -> Stream < 'a , (K , (V1 , V2)) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Join (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } pub fn anti_join < W2 > (self , n : Stream < 'a , K , W2 , C , N >) -> Stream < 'a , (K , V1) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("anti_join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: AntiJoin (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , K : Eq + Hash , V , N : Location > Stream < 'a , (K , V) , Bounded , Tick , N > { pub fn fold_keyed < A , I : Fn () -> A + 'a , F : Fn (& mut A , V) + 'a > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , A) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FoldKeyed { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce_keyed < F : Fn (& mut V , V) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , V) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: ReduceKeyed { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } pub fn get_this_crate () -> TokenStream { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , Span :: call_site ()) ; quote ! { # ident } } } } pub fn serialize_bincode < T : Serialize > (is_demux : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if is_demux { parse_quote ! { map (| (id , data) | { (id , # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into ()) }) } } else { parse_quote ! { map (| data | { # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into () }) } } } pub fn deserialize_bincode < T : DeserializeOwned > (tagged : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if tagged { parse_quote ! { map (| res | { let (id , b) = res . unwrap () ; (id , # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& b) . unwrap ()) }) } } else { parse_quote ! { map (| res | { # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& res . unwrap ()) . unwrap () }) } } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn send_bincode < N2 : Location , CoreType > (self , other : & N2 ,) -> Stream < 'a , N :: Out < CoreType > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T > , CoreType : Serialize + DeserializeOwned , { let serialize_pipeline = Some (serialize_bincode :: < CoreType > (N :: is_demux ())) ; let deserialize_pipeline = Some (deserialize_bincode :: < CoreType > (N :: is_tagged ())) ; Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bytes < N2 : Location > (self , other : & N2 ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T > , { Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline : None , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline : if N :: is_tagged () { Some (parse_quote ! (map (| (id , b) | (id , b . unwrap () . freeze ())))) } else { Some (parse_quote ! (map (| b | b . unwrap () . freeze ()))) } , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bincode_interleaved < N2 : Location , Tag , CoreType > (self , other : & N2 ,) -> Stream < 'a , CoreType , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T , Out < CoreType > = (Tag , CoreType) > , CoreType : Serialize + DeserializeOwned , { self . send_bincode :: < N2 , CoreType > (other) . map (q ! (| (_ , b) | b)) } pub fn send_bytes_interleaved < N2 : Location , Tag > (self , other : & N2 ,) -> Stream < 'a , Bytes , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T , Out < Bytes > = (Tag , Bytes) > , { self . send_bytes :: < N2 > (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bincode < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < T > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) > , T : Clone + Serialize + DeserializeOwned , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bincode (other) } pub fn broadcast_bincode_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , T , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) , Out < T > = (Tag , T) > + 'a , T : Clone + Serialize + DeserializeOwned , { self . broadcast_bincode (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bytes < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) > + 'a , T : Clone , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bytes (other) } pub fn broadcast_bytes_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , Bytes , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) , Out < Bytes > = (Tag , Bytes) > + 'a , T : Clone , { self . broadcast_bytes (other) . map (q ! (| (_ , b) | b)) } } } pub use stream :: { Bounded , NoTick , Stream , Tick , Unbounded } ; pub mod singleton { pub use std :: cell :: RefCell ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use crate :: builder :: FlowLeaves ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial , CycleComplete } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: Stream ; pub use crate :: singleton :: CrossResult ; # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Singleton < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Singleton :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } pub use crate :: singleton :: Singleton ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Singleton { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleComplete < 'a > for Singleton < 'a , T , Bounded , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleCollectionWithInitial < 'a > for Singleton < 'a , T , Bounded , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , initial : Self , l : LocationId ,) -> Self { Singleton :: new (l , ir_leaves , HfPlusNode :: Union (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , }) , initial . ir_node . into_inner () . into () ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Singleton < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Singleton { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , U , W , C , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (Self :: other_ir_node (other)) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Singleton < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CrossSingleton (Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , Box :: new (HfPlusNode :: Unpersist (Box :: new (Self :: other_ir_node (other)))) ,))) ,) } } pub use crate :: singleton :: Optional ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Optional { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } pub fn some (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: new (singleton . location_kind , singleton . ir_leaves , singleton . ir_node . into_inner () ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > From < Singleton < 'a , T , W , C , N > > for Optional < 'a , T , W , C , N > { fn from (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: some (singleton) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Optional < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Optional { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn into_stream (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , Tick , N > > ,) -> Optional < 'a , (T , O) , Bounded , Tick , N > where O : Clone , { let other : Optional < 'a , O , Bounded , Tick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn union (self , other : Optional < 'a , T , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Optional < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_samples (self) -> Stream < 'a , T , Unbounded , NoTick , N > { self . latest_tick () . all_ticks () } pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . latest_tick () . continue_if (samples . first ()) . latest () . tick_samples () } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Unbounded , NoTick , N > > ,) -> Optional < 'a , (T , O) , Unbounded , NoTick , N > where O : Clone , { let other : Optional < 'a , O , Unbounded , NoTick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } self . latest_tick () . cross_singleton (other . latest_tick ()) . latest () } } } pub use singleton :: { Optional , Singleton } ; pub mod location { pub use std :: marker :: PhantomData ; pub use crate :: location :: LocationId ; pub use crate :: location :: Location ; pub use crate :: location :: Process ; # [cfg (stageleft_macro)] impl < P > Clone for Process < P > { fn clone (& self) -> Self { Process { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < P > Location for Process < P > { fn id (& self) -> LocationId { LocationId :: Process (self . id) } } pub use crate :: location :: Cluster ; # [cfg (stageleft_macro)] impl < C > Clone for Cluster < C > { fn clone (& self) -> Self { Cluster { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < C > Location for Cluster < C > { fn id (& self) -> LocationId { LocationId :: Cluster (self . id) } } pub use crate :: location :: CanSend ; # [cfg (stageleft_macro)] impl < P1 , P2 > CanSend < Process < P2 > > for Process < P1 > { type In < T > = T ; type Out < T > = T ; fn is_demux () -> bool { false } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < P1 , C2 > CanSend < Cluster < C2 > > for Process < P1 > { type In < T > = (u32 , T) ; type Out < T > = T ; fn is_demux () -> bool { true } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < C1 , P2 > CanSend < Process < P2 > > for Cluster < C1 > { type In < T > = T ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { false } fn is_tagged () -> bool { true } } # [cfg (stageleft_macro)] impl < C1 , C2 > CanSend < Cluster < C2 > > for Cluster < C1 > { type In < T > = (u32 , T) ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { true } fn is_tagged () -> bool { true } } } pub use location :: { Cluster , Process } ; pub mod deploy { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use stageleft :: Quoted ; pub mod graphs { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use super :: { LocalDeploy , Node , ProcessSpec } ; pub use crate :: deploy :: graphs :: SingleProcessGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for SingleProcessGraph { type Process = SingleNode ; type Cluster = SingleNode ; type Meta = () ; type GraphId = () ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { SingleNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { SingleNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , SingleProcessGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> SingleNode { SingleNode { } } } pub use crate :: deploy :: graphs :: SingleNode ; # [cfg (stageleft_macro)] impl Node for SingleNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } pub use crate :: deploy :: graphs :: MultiGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for MultiGraph { type Process = MultiNode ; type Cluster = MultiNode ; type Meta = () ; type GraphId = usize ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { MultiNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { MultiNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , MultiGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> MultiNode { MultiNode { } } } pub use crate :: deploy :: graphs :: MultiNode ; # [cfg (stageleft_macro)] impl Node for MultiNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } } pub use graphs :: * ; pub use crate :: deploy :: LocalDeploy ; pub use crate :: deploy :: Deploy ; # [cfg (stageleft_macro)] impl < 'a , T : Deploy < 'a , Process = N , Cluster = C , Meta = M , GraphId = R > , N : Node < Meta = M > , C : Node < Meta = M > , M : Default , R , > LocalDeploy < 'a > for T { type Process = N ; type Cluster = C ; type Meta = M ; type GraphId = R ; fn has_trivial_node () -> bool { < T as Deploy < 'a > > :: has_trivial_node () } fn trivial_process (id : usize) -> Self :: Process { < T as Deploy < 'a > > :: trivial_process (id) } fn trivial_cluster (id : usize) -> Self :: Cluster { < T as Deploy < 'a > > :: trivail_cluster (id) } } pub use crate :: deploy :: ProcessSpec ; pub use crate :: deploy :: ClusterSpec ; pub use crate :: deploy :: Node ; } pub use deploy :: { ClusterSpec , Deploy , ProcessSpec } ; pub mod cycle { pub use std :: marker :: PhantomData ; pub use crate :: builder :: FlowLeaves ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: cycle :: CycleComplete ; pub use crate :: cycle :: CycleCollection ; pub use crate :: cycle :: CycleCollectionWithInitial ; pub use crate :: cycle :: HfCycle ; # [cfg (stageleft_macro)] impl < 'a , S : CycleComplete < 'a > > HfCycle < 'a , S > { pub fn complete (self , stream : S) { let ident = self . ident ; S :: complete (stream , ident) } } } pub use cycle :: HfCycle ; pub mod builder { pub use std :: cell :: RefCell ; pub use std :: collections :: HashMap ; pub use std :: marker :: PhantomData ; pub use std :: rc :: Rc ; pub use std :: time :: Duration ; pub use hydroflow :: futures :: stream :: Stream as FuturesStream ; pub use hydroflow :: { tokio , tokio_stream } ; pub use internal :: TokenStream ; pub use proc_macro2 :: Span ; pub use quote :: quote ; pub use runtime_support :: FreeVariable ; pub use stageleft :: * ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Cluster , Location , LocationId , Process } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: { HfCycle , Optional , RuntimeContext , Singleton , Stream } ; pub mod built { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use hydroflow_lang :: graph :: { eliminate_extra_unions_tees , HydroflowGraph } ; pub use super :: deploy :: { DeployFlow , DeployResult } ; pub use crate :: deploy :: { ClusterSpec , Deploy , LocalDeploy , ProcessSpec } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Cluster , Process } ; pub use crate :: HfCompiled ; pub use crate :: builder :: built :: BuiltFlow ; # [cfg (stageleft_macro)] impl < 'a > Drop for BuiltFlow < 'a > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped BuiltFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn ir (& self) -> & Vec < HfPlusLeaf < 'a > > { & self . ir } pub fn optimize_with (mut self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> BuiltFlow < 'a > { self . used = true ; BuiltFlow { ir : f (std :: mem :: take (& mut self . ir)) , processes : std :: mem :: take (& mut self . processes) , clusters : std :: mem :: take (& mut self . clusters) , used : false , _phantom : PhantomData , } } } pub fn build_inner (ir : & mut Vec < HfPlusLeaf >) -> BTreeMap < usize , HydroflowGraph > { let mut builders = BTreeMap :: new () ; let mut built_tees = HashMap :: new () ; let mut next_stmt_id = 0 ; for leaf in ir { leaf . emit (& mut builders , & mut built_tees , & mut next_stmt_id) ; } builders . into_iter () . map (| (k , v) | { let (mut flat_graph , _ , _) = v . build () ; eliminate_extra_unions_tees (& mut flat_graph) ; (k , flat_graph) }) . collect () } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn compile_no_network < D : LocalDeploy < 'a > > (mut self) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; HfCompiled { hydroflow_ir : build_inner (& mut self . ir) , extra_stmts : BTreeMap :: new () , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> BuiltFlow < 'a > { self . optimize_with (crate :: persist_pullup :: persist_pullup) } fn into_deploy < D : LocalDeploy < 'a > > (mut self) -> DeployFlow < 'a , D > { self . used = true ; let processes = if D :: has_trivial_node () { self . processes . iter () . map (| id | (* id , D :: trivial_process (* id))) . collect () } else { HashMap :: new () } ; let clusters = if D :: has_trivial_node () { self . clusters . iter () . map (| id | (* id , D :: trivial_cluster (* id))) . collect () } else { HashMap :: new () } ; DeployFlow { ir : std :: mem :: take (& mut self . ir) , nodes : processes , clusters , used : false , _phantom : PhantomData , } } pub fn with_process < P , D : LocalDeploy < 'a > > (self , process : & Process < P > , spec : impl ProcessSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_process (process , spec) } pub fn with_cluster < C , D : LocalDeploy < 'a > > (self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_cluster (cluster , spec) } pub fn compile < D : Deploy < 'a > + 'a > (self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . into_deploy :: < D > () . compile (env) } pub fn deploy < D : Deploy < 'a , CompileEnv = () > + 'a > (self , env : & mut D :: InstantiateEnv ,) -> DeployResult < 'a , D > { self . into_deploy :: < D > () . deploy (env) } } } pub mod deploy { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use proc_macro2 :: Span ; pub use stageleft :: Quoted ; pub use super :: built :: build_inner ; pub use crate :: deploy :: { LocalDeploy , Node } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: { Cluster , ClusterSpec , Deploy , HfCompiled , Process , ProcessSpec } ; pub use crate :: builder :: deploy :: DeployFlow ; # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > Drop for DeployFlow < 'a , D > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped DeployFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > DeployFlow < 'a , D > { pub fn with_process < P > (mut self , process : & Process < P > , spec : impl ProcessSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < P > () . to_string () ; self . nodes . insert (process . id , spec . build (process . id , & tag_name)) ; self } pub fn with_cluster < C > (mut self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < C > () . to_string () ; self . clusters . insert (cluster . id , spec . build (cluster . id , & tag_name)) ; self } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployFlow < 'a , D > { pub fn compile (mut self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; let mut seen_tees : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | leaf . compile_network :: < D > (env , & mut seen_tees , & self . nodes , & self . clusters)) . collect () ; let extra_stmts = self . extra_stmts (env) ; HfCompiled { hydroflow_ir : build_inner (& mut ir_leaves_networked) , extra_stmts , _phantom : PhantomData , } } fn extra_stmts (& self , env : & < D as Deploy < 'a > > :: CompileEnv) -> BTreeMap < usize , Vec < syn :: Stmt > > { let all_locations_count = self . nodes . len () + self . clusters . len () ; let mut extra_stmts : BTreeMap < usize , Vec < syn :: Stmt > > = BTreeMap :: new () ; for & c_id in self . clusters . keys () { let self_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , c_id) , Span :: call_site () ,) ; let self_id_expr = D :: cluster_self_id (env) . splice () ; extra_stmts . entry (c_id) . or_default () . push (syn :: parse_quote ! { let # self_id_ident = # self_id_expr ; }) ; for other_location in 0 .. all_locations_count { let other_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , c_id) , Span :: call_site () ,) ; let other_id_expr = D :: cluster_ids (env , c_id) . splice () ; extra_stmts . entry (other_location) . or_default () . push (syn :: parse_quote ! { let # other_id_ident = # other_id_expr ; }) ; } } extra_stmts } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a , CompileEnv = () > > DeployFlow < 'a , D > { # [must_use] pub fn deploy (mut self , env : & mut D :: InstantiateEnv) -> DeployResult < 'a , D > { self . used = true ; let mut seen_tees_instantiate : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | { leaf . compile_network :: < D > (& () , & mut seen_tees_instantiate , & self . nodes , & self . clusters ,) }) . collect () ; let mut compiled = build_inner (& mut ir_leaves_networked) ; let mut extra_stmts = self . extra_stmts (& ()) ; let mut meta = D :: Meta :: default () ; let (mut processes , mut clusters) = (std :: mem :: take (& mut self . nodes) . into_iter () . map (| (node_id , node) | { node . instantiate (env , & mut meta , compiled . remove (& node_id) . unwrap () , extra_stmts . remove (& node_id) . unwrap_or_default () ,) ; (node_id , node) }) . collect :: < HashMap < _ , _ > > () , std :: mem :: take (& mut self . clusters) . into_iter () . map (| (cluster_id , cluster) | { cluster . instantiate (env , & mut meta , compiled . remove (& cluster_id) . unwrap () , extra_stmts . remove (& cluster_id) . unwrap_or_default () ,) ; (cluster_id , cluster) }) . collect :: < HashMap < _ , _ > > () ,) ; for node in processes . values_mut () { node . update_meta (& meta) ; } for cluster in clusters . values_mut () { cluster . update_meta (& meta) ; } let mut seen_tees_connect = HashMap :: new () ; for leaf in ir_leaves_networked { leaf . connect_network (& mut seen_tees_connect) ; } DeployResult { processes , clusters , } } } pub use crate :: builder :: deploy :: DeployResult ; # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployResult < 'a , D > { pub fn get_process < P > (& self , p : & Process < P >) -> & D :: Process { let id = match p . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . processes . get (& id) . unwrap () } pub fn get_cluster < C > (& self , c : & Cluster < C >) -> & D :: Cluster { let id = match c . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . clusters . get (& id) . unwrap () } } } # [doc = " Tracks the leaves of the dataflow IR. This is referenced by"] # [doc = " `Stream` and `HfCycle` to build the IR. The inner option will"] # [doc = " be set to `None` when this builder is finalized."] pub type FlowLeaves < 'a > = Rc < RefCell < Option < Vec < HfPlusLeaf < 'a > > > > > ; pub use crate :: builder :: ClusterIds ; # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Vec < u32 > > for ClusterIds < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , & 'a Vec < u32 > > for ClusterIds < 'a > { } # [derive (Copy , Clone)] pub struct ClusterSelfId < 'a > { pub id : usize , pub _phantom : PhantomData < & 'a mut & 'a u32 > , } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < u32 > for ClusterSelfId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , u32 > for ClusterSelfId < 'a > { } pub use crate :: builder :: FlowBuilder ; # [cfg (stageleft_macro)] impl < 'a > Drop for FlowBuilder < 'a > { fn drop (& mut self) { if ! self . finalized { panic ! ("Dropped FlowBuilder without finalizing, you may have forgotten to call `with_default_optimize`, `optimize_with`, or `finalize`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > QuotedContext for FlowBuilder < 'a > { fn create () -> Self { FlowBuilder :: new () } } # [cfg (stageleft_macro)] impl < 'a > FlowBuilder < 'a > { # [allow (clippy :: new_without_default)] pub fn new () -> FlowBuilder < 'a > { FlowBuilder { ir_leaves : Rc :: new (RefCell :: new (Some (Vec :: new ()))) , nodes : RefCell :: new (vec ! []) , clusters : RefCell :: new (vec ! []) , cycle_ids : RefCell :: new (HashMap :: new ()) , next_node_id : RefCell :: new (0) , finalized : false , _phantom : PhantomData , } } pub fn finalize (mut self) -> built :: BuiltFlow < 'a > { self . finalized = true ; built :: BuiltFlow { ir : self . ir_leaves . borrow_mut () . take () . unwrap () , processes : self . nodes . replace (vec ! []) , clusters : self . clusters . replace (vec ! []) , used : false , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> built :: BuiltFlow < 'a > { self . finalize () . with_default_optimize () } pub fn optimize_with (self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> built :: BuiltFlow < 'a > { self . finalize () . optimize_with (f) } pub fn ir_leaves (& self) -> & FlowLeaves < 'a > { & self . ir_leaves } pub fn process < P > (& self) -> Process < P > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . nodes . borrow_mut () . push (id) ; Process { id , _phantom : PhantomData , } } pub fn cluster < C > (& self) -> Cluster < C > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . clusters . borrow_mut () . push (id) ; Cluster { id , _phantom : PhantomData , } } pub fn runtime_context (& self) -> RuntimeContext < 'a > { RuntimeContext { _phantom : PhantomData , } } pub fn cluster_members < C > (& self , cluster : & Cluster < C > ,) -> impl Quoted < 'a , & 'a Vec < u32 > > + Copy + 'a { ClusterIds { id : cluster . id , _phantom : PhantomData , } } pub fn cluster_self_id < C > (& self , cluster : & Cluster < C >) -> impl Quoted < 'a , u32 > + Copy + 'a { ClusterSelfId { id : cluster . id , _phantom : PhantomData , } } pub fn spin < L : Location > (& self , on : & L) -> Stream < 'a , () , Unbounded , NoTick , L > { Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Spin () , location_kind : on . id () , })) ,) } pub fn spin_batch < L : Location > (& self , on : & L , batch_size : impl Quoted < 'a , usize > + Copy + 'a ,) -> Stream < 'a , () , Bounded , Tick , L > { self . spin (on) . flat_map (q ! (move | _ | 0 .. batch_size)) . map (q ! (| _ | ())) . tick_batch () } pub fn source_stream < T , E : FuturesStream < Item = T > + Unpin , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Unbounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Stream (e . into ()) , location_kind : on . id () , })) ,) } pub fn source_iter < T , E : IntoIterator < Item = T > , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Bounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , })) ,) } pub fn singleton < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Singleton < 'a , T , Bounded , NoTick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Singleton :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,)))) ,) } pub fn singleton_first_tick < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Optional < 'a , T , Bounded , Tick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,) } pub fn source_interval < L : Location > (& self , on : & L , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , () , Unbounded , NoTick , L > { let interval = interval . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : on . id () , })) ,) } pub fn source_interval_delayed < L : Location > (& self , on : & L , delay : impl Quoted < 'a , Duration > + Copy + 'a , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , tokio :: time :: Instant , Unbounded , NoTick , L > { self . source_stream (on , q ! (tokio_stream :: wrappers :: IntervalStream :: new (tokio :: time :: interval_at (tokio :: time :: Instant :: now () + delay , interval))) ,) . tick_batch () . first () . latest () } pub fn cycle < S : CycleCollection < 'a > > (& self , on : & S :: Location) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , on . id ()) ,) } pub fn cycle_with_initial < S : CycleCollectionWithInitial < 'a > > (& self , on : & S :: Location , initial : S ,) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , initial , on . id ()) ,) } } } pub use builder :: FlowBuilder ; pub mod ir { pub use core :: panic ; pub use std :: cell :: RefCell ; pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow_lang :: graph :: FlatGraphBuilder ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: ToTokens ; pub use syn :: parse_quote ; pub use crate :: deploy :: Deploy ; pub use crate :: location :: LocationId ; pub use crate :: ir :: DebugExpr ; # [cfg (stageleft_macro)] impl From < syn :: Expr > for DebugExpr { fn from (expr : syn :: Expr) -> DebugExpr { DebugExpr (expr) } } # [cfg (stageleft_macro)] impl Deref for DebugExpr { type Target = syn :: Expr ; fn deref (& self) -> & Self :: Target { & self . 0 } } # [cfg (stageleft_macro)] impl ToTokens for DebugExpr { fn to_tokens (& self , tokens : & mut TokenStream) { self . 0 . to_tokens (tokens) ; } } # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugExpr { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "{}" , self . 0 . to_token_stream ()) } } pub use crate :: ir :: DebugInstantiate ; # [cfg (stageleft_macro)] impl < 'a > std :: fmt :: Debug for DebugInstantiate < 'a > { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<network instantiate>") } } pub use crate :: ir :: DebugPipelineFn ; # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugPipelineFn { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<function>") } } pub use crate :: ir :: HfPlusSource ; pub use crate :: ir :: HfPlusLeaf ; # [cfg (stageleft_macro)] impl < 'a > HfPlusLeaf < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . compile_network :: < D > (compile_env , s , nodes , clusters) ; } , seen_tees ,) } pub fn connect_network (self , seen_tees : & mut SeenTees < 'a >) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . connect_network (s) ; } , seen_tees ,) } pub fn transform_children (self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) -> HfPlusLeaf < 'a > { match self { HfPlusLeaf :: ForEach { f , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: ForEach { f , input } } HfPlusLeaf :: DestSink { sink , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: DestSink { sink , input } } HfPlusLeaf :: CycleSink { ident , location_kind , mut input , } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: CycleSink { ident , location_kind , input , } } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) { match self { HfPlusLeaf :: ForEach { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> for_each (# f) ; }) ; } HfPlusLeaf :: DestSink { sink , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink) ; }) ; } HfPlusLeaf :: CycleSink { ident , location_kind , input , } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; assert_eq ! (input_location_id , * location_id , "cycle_sink location mismatch") ; graph_builders . entry (* location_id) . or_default () . add_statement (parse_quote ! { # ident = # input_ident ; }) ; } } } } pub use crate :: ir :: HfPlusNode ; pub type SeenTees < 'a > = HashMap < * const RefCell < HfPlusNode < 'a > > , Rc < RefCell < HfPlusNode < 'a > > > > ; # [cfg (stageleft_macro)] impl < 'a > HfPlusNode < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (& mut self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) { self . transform_children (| n , s | n . compile_network :: < D > (compile_env , s , nodes , clusters) , seen_tees ,) ; if let HfPlusNode :: Network { from_location , to_location , instantiate_fn , .. } = self { let (sink_expr , source_expr , connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { let ((sink , source) , connect_fn) = match (from_location , to_location) { (LocationId :: Process (from) , LocationId :: Process (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: o2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Process (from) , LocationId :: Cluster (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: o2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Process (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: m2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Cluster (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: m2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } } ; (sink , source , connect_fn) } DebugInstantiate :: Finalized (_ , _ , _) => panic ! ("network already finalized") , } ; * instantiate_fn = DebugInstantiate :: Finalized (sink_expr , source_expr , connect_fn) ; } } pub fn connect_network (& mut self , seen_tees : & mut SeenTees < 'a >) { self . transform_children (| n , s | n . connect_network (s) , seen_tees) ; if let HfPlusNode :: Network { instantiate_fn , .. } = self { match instantiate_fn { DebugInstantiate :: Building () => panic ! ("network not built") , DebugInstantiate :: Finalized (_ , _ , ref connect_fn) => { connect_fn () ; } } } } pub fn transform_children (& mut self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) { match self { HfPlusNode :: Placeholder => { panic ! () ; } HfPlusNode :: Source { .. } => { } HfPlusNode :: CycleSource { .. } => { } HfPlusNode :: Tee { inner } => { if let Some (transformed) = seen_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { * inner = transformed . clone () ; } else { let transformed_cell = Rc :: new (RefCell :: new (HfPlusNode :: Placeholder)) ; seen_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , transformed_cell . clone () ,) ; let mut orig = inner . replace (HfPlusNode :: Placeholder) ; transform (& mut orig , seen_tees) ; * transformed_cell . borrow_mut () = orig ; * inner = transformed_cell ; } } HfPlusNode :: Persist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Unpersist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Delta (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Union (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossProduct (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossSingleton (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Join (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Difference (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: AntiJoin (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Map { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FlatMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Filter { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FilterMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Sort (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: DeferTick (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Enumerate (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Inspect { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Unique (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Fold { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FoldKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Reduce { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: ReduceKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Network { input , .. } => { transform (input . as_mut () , seen_tees) ; } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) -> (syn :: Ident , usize) { match self { HfPlusNode :: Placeholder => { panic ! () } HfPlusNode :: Persist (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let persist_id = * next_stmt_id ; * next_stmt_id += 1 ; let persist_ident = syn :: Ident :: new (& format ! ("stream_{}" , persist_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # persist_ident = # inner_ident -> persist ::<'static > () ; }) ; (persist_ident , location) } HfPlusNode :: Unpersist (_) => { panic ! ("Unpersist is a marker node and should have been optimized away. This is likely a compiler bug.") } HfPlusNode :: Delta (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let delta_id = * next_stmt_id ; * next_stmt_id += 1 ; let delta_ident = syn :: Ident :: new (& format ! ("stream_{}" , delta_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # delta_ident = # inner_ident -> multiset_delta () ; }) ; (delta_ident , location) } HfPlusNode :: Source { source , location_kind , } => { let source_id = * next_stmt_id ; * next_stmt_id += 1 ; let source_ident = syn :: Ident :: new (& format ! ("stream_{}" , source_id) , Span :: call_site ()) ; let source_stmt = match source { HfPlusSource :: Stream (expr) => { parse_quote ! { # source_ident = source_stream (# expr) ; } } HfPlusSource :: Iter (expr) => { parse_quote ! { # source_ident = source_iter (# expr) ; } } HfPlusSource :: Interval (expr) => { parse_quote ! { # source_ident = source_interval (# expr) ; } } HfPlusSource :: Spin () => { parse_quote ! { # source_ident = spin () ; } } } ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; graph_builders . entry (* location_id) . or_default () . add_statement (source_stmt) ; (source_ident , * location_id) } HfPlusNode :: CycleSource { ident , location_kind , } => { let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; (ident . clone () , * location_id) } HfPlusNode :: Tee { inner } => { if let Some (ret) = built_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { ret . clone () } else { let (inner_ident , inner_location_id) = inner . borrow () . emit (graph_builders , built_tees , next_stmt_id) ; let tee_id = * next_stmt_id ; * next_stmt_id += 1 ; let tee_ident = syn :: Ident :: new (& format ! ("stream_{}" , tee_id) , Span :: call_site ()) ; let builder = graph_builders . entry (inner_location_id) . or_default () ; builder . add_statement (parse_quote ! { # tee_ident = # inner_ident -> tee () ; }) ; built_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , (tee_ident . clone () , inner_location_id) ,) ; (tee_ident , inner_location_id) } } HfPlusNode :: Union (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "union inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let union_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # union_ident = union () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [0] # union_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # union_ident ; }) ; (union_ident , left_location_id) } HfPlusNode :: CrossSingleton (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "cross_singleton inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let cross_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # cross_ident = cross_singleton () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [input] # cross_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [single] # cross_ident ; }) ; (cross_ident , left_location_id) } HfPlusNode :: CrossProduct (..) | HfPlusNode :: Join (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: CrossProduct (..)) { parse_quote ! (cross_join_multiset) } else { parse_quote ! (join_multiset) } ; let (HfPlusNode :: CrossProduct (left , right) | HfPlusNode :: Join (left , right)) = self else { unreachable ! () } ; let (left_inner , left_was_persist) = if let HfPlusNode :: Persist (left) = left . as_ref () { (left , true) } else { (left , false) } ; let (right_inner , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left_inner . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right_inner . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "join / cross product inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; match (left_was_persist , right_was_persist) { (true , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'static > () ; }) ; } (true , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'tick > () ; }) ; } (false , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } (false , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } } ; builder . add_statement (parse_quote ! { # left_ident -> [0] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Difference (..) | HfPlusNode :: AntiJoin (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Difference (..)) { parse_quote ! (difference_multiset) } else { parse_quote ! (anti_join_multiset) } ; let (HfPlusNode :: Difference (left , right) | HfPlusNode :: AntiJoin (left , right)) = self else { unreachable ! () } ; let (right , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "difference / anti join inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; if right_was_persist { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } else { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } builder . add_statement (parse_quote ! { # left_ident -> [pos] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [neg] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Map { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let map_id = * next_stmt_id ; * next_stmt_id += 1 ; let map_ident = syn :: Ident :: new (& format ! ("stream_{}" , map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # map_ident = # input_ident -> map (# f) ; }) ; (map_ident , input_location_id) } HfPlusNode :: FlatMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let flat_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let flat_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , flat_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # flat_map_ident = # input_ident -> flat_map (# f) ; }) ; (flat_map_ident , input_location_id) } HfPlusNode :: Filter { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_ident = # input_ident -> filter (# f) ; }) ; (filter_ident , input_location_id) } HfPlusNode :: FilterMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_map_ident = # input_ident -> filter_map (# f) ; }) ; (filter_map_ident , input_location_id) } HfPlusNode :: Sort (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sort_id = * next_stmt_id ; * next_stmt_id += 1 ; let sort_ident = syn :: Ident :: new (& format ! ("stream_{}" , sort_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # sort_ident = # input_ident -> sort () ; }) ; (sort_ident , input_location_id) } HfPlusNode :: DeferTick (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let defer_tick_id = * next_stmt_id ; * next_stmt_id += 1 ; let defer_tick_ident = syn :: Ident :: new (& format ! ("stream_{}" , defer_tick_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # defer_tick_ident = # input_ident -> defer_tick_lazy () ; }) ; (defer_tick_ident , input_location_id) } HfPlusNode :: Enumerate (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let enumerate_id = * next_stmt_id ; * next_stmt_id += 1 ; let enumerate_ident = syn :: Ident :: new (& format ! ("stream_{}" , enumerate_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # enumerate_ident = # input_ident -> enumerate () ; }) ; (enumerate_ident , input_location_id) } HfPlusNode :: Inspect { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let inspect_id = * next_stmt_id ; * next_stmt_id += 1 ; let inspect_ident = syn :: Ident :: new (& format ! ("stream_{}" , inspect_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # inspect_ident = # input_ident -> inspect (# f) ; }) ; (inspect_ident , input_location_id) } HfPlusNode :: Unique (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let unique_id = * next_stmt_id ; * next_stmt_id += 1 ; let unique_ident = syn :: Ident :: new (& format ! ("stream_{}" , unique_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # unique_ident = # input_ident -> unique ::<'tick > () ; }) ; (unique_ident , input_location_id) } HfPlusNode :: Fold { .. } | HfPlusNode :: FoldKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Fold { .. }) { parse_quote ! (fold) } else { parse_quote ! (fold_keyed) } ; let (HfPlusNode :: Fold { init , acc , input } | HfPlusNode :: FoldKeyed { init , acc , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let fold_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'static > (# init , # acc) ; }) ; } else { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'tick > (# init , # acc) ; }) ; } (fold_ident , input_location_id) } HfPlusNode :: Reduce { .. } | HfPlusNode :: ReduceKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Reduce { .. }) { parse_quote ! (reduce) } else { parse_quote ! (reduce_keyed) } ; let (HfPlusNode :: Reduce { f , input } | HfPlusNode :: ReduceKeyed { f , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let reduce_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'static > (# f) ; }) ; } else { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'tick > (# f) ; }) ; } (reduce_ident , input_location_id) } HfPlusNode :: Network { from_location : _ , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input , } => { let (sink_expr , source_expr , _connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { panic ! ("Expected the network to be finalized") } DebugInstantiate :: Finalized (sink , source , connect_fn) => { (sink , source , connect_fn) } } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sender_builder = graph_builders . entry (input_location_id) . or_default () ; if let Some (serialize_pipeline) = serialize_pipeline { sender_builder . add_statement (parse_quote ! { # input_ident -> # serialize_pipeline -> dest_sink (# sink_expr) ; }) ; } else { sender_builder . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink_expr) ; }) ; } let to_id = match to_location { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let receiver_builder = graph_builders . entry (* to_id) . or_default () ; let receiver_stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let receiver_stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , receiver_stream_id) , Span :: call_site ()) ; if let Some (deserialize_pipeline) = deserialize_pipeline { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) -> # deserialize_pipeline ; }) ; } else { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) ; }) ; } (receiver_stream_ident , * to_id) } } } } } pub mod persist_pullup { pub use std :: cell :: RefCell ; pub use std :: collections :: HashSet ; pub use std :: ops :: Deref ; pub use crate :: ir :: * ; pub fn persist_pullup_node < 'a > (node : & mut HfPlusNode < 'a > , seen_tees : & mut SeenTees < 'a > , persist_pulled_tees : & mut HashSet < * const RefCell < HfPlusNode < 'a > > > ,) { node . transform_children (| n , s | persist_pullup_node (n , s , persist_pulled_tees) , seen_tees ,) ; match node { HfPlusNode :: Unpersist (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Unpersist (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Delta (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Delta (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Tee { inner } => { if persist_pulled_tees . contains (& (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >)) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } else { let inner_borrow = inner . borrow () ; if let HfPlusNode :: Persist (_) = inner_borrow . deref () { drop (inner_borrow) ; persist_pulled_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >) ; if let HfPlusNode :: Persist (box behind_persist) = inner . replace (HfPlusNode :: Placeholder) { * inner . borrow_mut () = behind_persist ; } else { unreachable ! () } * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } } } HfPlusNode :: Map { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Map { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Map { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: FlatMap { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: FlatMap { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: FlatMap { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Filter { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Filter { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Filter { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Network { input : box HfPlusNode :: Persist (_) , .. } => { if let HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Union (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Union (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Union (left , right))) ; } else { unreachable ! () } } HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: CrossProduct (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,) ,)))) ; } else { unreachable ! () } } HfPlusNode :: Join (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Join (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: Join (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,))))) ; } else { unreachable ! () } } _ => { } } } pub fn persist_pullup (ir : Vec < HfPlusLeaf >) -> Vec < HfPlusLeaf > { let mut seen_tees = Default :: default () ; let mut persist_pulled_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| n , s | persist_pullup_node (n , s , & mut persist_pulled_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn persist_pullup_through_map () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } # [test] fn persist_pullup_behind_tee () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; let before_tee = flow . source_iter (& process , q ! (0 .. 10)) . tick_batch () . persist () ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } } } pub mod profiler { pub use std :: cell :: RefCell ; pub use hydroflow :: futures :: channel :: mpsc :: UnboundedSender ; pub use stageleft :: * ; pub use crate as hydroflow_plus ; pub use crate :: ir :: * ; pub use crate :: RuntimeContext ; pub fn increment_counter (count : & mut u64) { * count += 1 ; } pub fn quoted_any_fn < 'a , F : Fn (& usize) + 'a , Q : IntoQuotedMut < 'a , F > > (q : Q) -> Q { q } # [doc = " Add a profiling node before each node to count the cardinality of its input"] pub fn add_profiling_node < 'a > (node : & mut HfPlusNode < 'a > , _context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > , id : & mut u32 , seen_tees : & mut SeenTees < 'a > ,) { let my_id = * id ; * id += 1 ; node . transform_children (| node , seen_tees | { add_profiling_node (node , _context , counters , counter_queue , id , seen_tees) } , seen_tees ,) ; let orig_node = std :: mem :: replace (node , HfPlusNode :: Placeholder) ; * node = HfPlusNode :: Inspect { f : quoted_any_fn (q ! ({ counter_queue . borrow () . unbounded_send ((my_id as usize , counters . borrow () [my_id as usize])) . unwrap () ; counters . borrow_mut () [my_id as usize] = 0 ; move | _ | { hydroflow_plus :: profiler :: increment_counter (& mut counters . borrow_mut () [my_id as usize] ,) ; } })) . splice () . into () , input : Box :: new (orig_node) , } } # [doc = " Count the cardinality of each input and periodically output to a file"] pub fn profiling < 'a > (ir : Vec < HfPlusLeaf < 'a > > , context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > ,) -> Vec < HfPlusLeaf < 'a > > { let mut id = 0 ; let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | { add_profiling_node (node , context , counters , counter_queue , & mut id , seen_tees) } , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn profiler_wrapping_all_operators () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let runtime_context = flow . runtime_context () ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (& built . ir ()) ; let counters = RuntimeData :: new ("Fake") ; let counter_queue = RuntimeData :: new ("Fake") ; let pushed_down = built . with_default_optimize () . optimize_with (| ir | super :: profiling (ir , runtime_context , counters , counter_queue)) ; insta :: assert_debug_snapshot ! (& pushed_down . ir ()) ; let _ = pushed_down . compile_no_network :: < MultiGraph > () ; } } } pub mod properties { pub use std :: collections :: HashSet ; pub use stageleft :: * ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , SeenTees } ; pub use crate :: properties :: PropertyDatabase ; # [doc = " Allows us to convert the hydroflow datatype for folds to a binary operation for the algebra"] # [doc = " property tests."] # [allow (dead_code)] pub fn convert_hf_to_binary < I , A : Default , F : Fn (& mut A , I) > (f : F) -> impl Fn (I , I) -> A { move | a , b | { let mut acc = Default :: default () ; f (& mut acc , a) ; f (& mut acc , b) ; acc } } # [cfg (stageleft_macro)] impl PropertyDatabase { # [doc = " Tags the expression as commutative."] pub fn add_commutative_tag < 'a , I , A , F : Fn (& mut A , I) , Q : Quoted < 'a , F > + Clone > (& mut self , expr : Q ,) -> Q { let expr_clone = expr . clone () ; self . commutative . insert (expr_clone . splice ()) ; expr } pub fn is_tagged_commutative (& self , expr : & syn :: Expr) -> bool { self . commutative . contains (expr) } } pub fn properties_optimize_node < 'a > (node : & mut HfPlusNode < 'a > , db : & PropertyDatabase , seen_tees : & mut SeenTees < 'a > ,) { node . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , seen_tees ,) ; match node { HfPlusNode :: ReduceKeyed { f , .. } if db . is_tagged_commutative (& f . 0) => { dbg ! ("IDENTIFIED COMMUTATIVE OPTIMIZATION for {:?}" , & f) ; } _ => { } } } pub fn properties_optimize < 'a > (ir : Vec < HfPlusLeaf < 'a > > , db : & PropertyDatabase ,) -> Vec < HfPlusLeaf < 'a > > { let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use super :: * ; use crate :: deploy :: SingleProcessGraph ; use crate :: FlowBuilder ; # [test] fn test_property_database () { let mut db = PropertyDatabase :: default () ; assert ! (! db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; let _ = db . add_commutative_tag (q ! (| a : & mut i32 , b : i32 | * a += b)) ; assert ! (db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; } # [test] fn test_property_optimized () { let flow = FlowBuilder :: new () ; let mut database = PropertyDatabase :: default () ; let process = flow . process :: < () > () ; let counter_func = q ! (| count : & mut i32 , _ | * count += 1) ; let _ = database . add_commutative_tag (counter_func) ; flow . source_iter (& process , q ! (vec ! [])) . map (q ! (| string : String | (string , ()))) . tick_batch () . fold_keyed (q ! (|| 0) , counter_func) . all_ticks () . for_each (q ! (| (string , count) | println ! ("{}: {}" , string , count))) ; let built = flow . finalize () . optimize_with (| ir | properties_optimize (ir , & database)) . with_default_optimize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let _ = built . compile_no_network :: < SingleProcessGraph > () ; } } } pub use crate :: RuntimeContext ; # [cfg (stageleft_macro)] impl Copy for RuntimeContext < '_ > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Context > for RuntimeContext < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (quote ! (& context))) } } pub use crate :: HfCompiled ; # [cfg (stageleft_macro)] impl < 'a , ID > HfCompiled < 'a , ID > { pub fn hydroflow_ir (& self) -> & BTreeMap < usize , HydroflowGraph > { & self . hydroflow_ir } } # [cfg (stageleft_macro)] impl < 'a > HfCompiled < 'a , usize > { pub fn with_dynamic_id (self , id : impl Quoted < 'a , usize >) -> HfBuiltWithId < 'a > { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; let mut conditioned_tokens = None ; for (subgraph_id , flat_graph) in self . hydroflow_ir { let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; let my_extra_stmts = self . extra_stmts . get (& subgraph_id) . cloned () . unwrap_or_default () ; if let Some (conditioned_tokens) = conditioned_tokens . as_mut () { * conditioned_tokens = syn :: parse_quote ! { # conditioned_tokens else if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } } ; } else { conditioned_tokens = Some (syn :: parse_quote ! { if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } }) ; } } let conditioned_tokens : TokenStream = conditioned_tokens . unwrap () ; let id = id . splice () ; HfBuiltWithId { tokens : syn :: parse_quote ! ({ let __given_id = # id ; # conditioned_tokens else { panic ! ("Invalid node id: {}" , __given_id) ; } }) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfCompiled < 'a , () > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfCompiled < 'a , () > { fn to_tokens (mut self) -> (Option < TokenStream > , Option < TokenStream >) { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; if self . hydroflow_ir . len () != 1 { panic ! ("Expected exactly one subgraph in the Hydroflow IR") ; } let flat_graph = self . hydroflow_ir . remove (& 0) . unwrap () ; let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; (None , Some (tokens)) } } pub use crate :: HfBuiltWithId ; # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfBuiltWithId < 'a > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfBuiltWithId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (self . tokens)) } }
[INFO] [stdout] 1 + pub use std :: collections :: BTreeMap ; pub use std :: marker :: PhantomData ; pub use hydroflow :: scheduled :: context :: Context ; pub use hydroflow :: scheduled :: graph :: Hydroflow ; pub use hydroflow :: * ; pub use lang :: graph :: { partition_graph , HydroflowGraph } ; pub use proc_macro2 :: TokenStream ; pub use quote :: quote ; pub use stageleft :: runtime_support :: FreeVariable ; pub use stageleft :: Quoted ; pub mod runtime_support { pub use bincode ; } pub mod stream { pub use std :: cell :: RefCell ; pub use std :: hash :: Hash ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow :: bytes :: Bytes ; pub use hydroflow :: futures :: Sink ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: quote ; pub use serde :: de :: DeserializeOwned ; pub use serde :: Serialize ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use syn :: parse_quote ; pub use crate :: builder :: { ClusterIds , FlowLeaves } ; pub use crate :: cycle :: { CycleCollection , CycleComplete } ; pub use crate :: ir :: { DebugInstantiate , HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { CanSend , Location , LocationId } ; pub use crate :: { Cluster , Optional , Singleton } ; pub use crate :: stream :: Unbounded ; pub use crate :: stream :: Bounded ; pub use crate :: stream :: NoTick ; pub use crate :: stream :: Tick ; pub use crate :: stream :: Stream ; # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Stream { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Stream < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Stream { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , C , N > > ,) -> Stream < 'a , (T , O) , W , C , N > where O : Clone , { let other : Optional < 'a , O , Bounded , C , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn cross_product < O > (self , other : Stream < 'a , O , W , C , N >) -> Stream < 'a , (T , O) , W , C , N > where T : Clone , O : Clone , { if self . location_kind != other . location_kind { panic ! ("cross_product must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossProduct (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn union (self , other : Stream < 'a , T , W , C , N >) -> Stream < 'a , T , W , C , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn dest_sink < S : Unpin + Sink < T > + 'a > (self , sink : impl Quoted < 'a , S >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: DestSink { sink : sink . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn first (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } # [doc = " Allow this stream through if the other stream has elements, otherwise the output is empty."] pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } # [doc = " Allow this stream through if the other stream is empty, otherwise the output is empty."] pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn enumerate (self) -> Stream < 'a , (usize , T) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Enumerate (Box :: new (self . ir_node . into_inner ())) ,) } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn sort (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Ord , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Sort (Box :: new (self . ir_node . into_inner ())) ,) } pub fn count (self) -> Singleton < 'a , usize , Bounded , Tick , N > { self . fold (q ! (|| 0usize) , q ! (| count , _ | * count += 1)) } pub fn delta (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } pub fn unique (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Eq + Hash , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unique (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn tick_batch (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_prefix (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { self . tick_batch () . persist () } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn for_each < F : Fn (T) + 'a > (self , f : impl IntoQuotedMut < 'a , F >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: ForEach { input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , f : f . splice () . into () , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Unbounded , NoTick , N > { pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . tick_batch () . continue_if (samples . first ()) . all_ticks () } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Unbounded , NoTick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , C , N : Location > Stream < 'a , T , Bounded , C , N > { pub fn filter_not_in (self , other : Stream < 'a , T , Bounded , C , N >) -> Stream < 'a , T , Bounded , C , N > where T : Eq + Hash , { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Difference (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Stream < 'a , & T , W , C , N > { pub fn cloned (self) -> Stream < 'a , T , W , C , N > { self . map (q ! (| d | d . clone ())) } } # [cfg (stageleft_macro)] impl < 'a , K , V1 , W , C , N : Location > Stream < 'a , (K , V1) , W , C , N > { pub fn join < W2 , V2 > (self , n : Stream < 'a , (K , V2) , W2 , C , N > ,) -> Stream < 'a , (K , (V1 , V2)) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Join (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } pub fn anti_join < W2 > (self , n : Stream < 'a , K , W2 , C , N >) -> Stream < 'a , (K , V1) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("anti_join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: AntiJoin (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , K : Eq + Hash , V , N : Location > Stream < 'a , (K , V) , Bounded , Tick , N > { pub fn fold_keyed < A , I : Fn () -> A + 'a , F : Fn (& mut A , V) + 'a > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , A) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FoldKeyed { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce_keyed < F : Fn (& mut V , V) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , V) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: ReduceKeyed { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } pub fn get_this_crate () -> TokenStream { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , Span :: call_site ()) ; quote ! { # ident } } } } pub fn serialize_bincode < T : Serialize > (is_demux : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if is_demux { parse_quote ! { map (| (id , data) | { (id , # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into ()) }) } } else { parse_quote ! { map (| data | { # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into () }) } } } pub fn deserialize_bincode < T : DeserializeOwned > (tagged : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if tagged { parse_quote ! { map (| res | { let (id , b) = res . unwrap () ; (id , # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& b) . unwrap ()) }) } } else { parse_quote ! { map (| res | { # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& res . unwrap ()) . unwrap () }) } } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn send_bincode < N2 : Location , CoreType > (self , other : & N2 ,) -> Stream < 'a , N :: Out < CoreType > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T > , CoreType : Serialize + DeserializeOwned , { let serialize_pipeline = Some (serialize_bincode :: < CoreType > (N :: is_demux ())) ; let deserialize_pipeline = Some (deserialize_bincode :: < CoreType > (N :: is_tagged ())) ; Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bytes < N2 : Location > (self , other : & N2 ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T > , { Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline : None , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline : if N :: is_tagged () { Some (parse_quote ! (map (| (id , b) | (id , b . unwrap () . freeze ())))) } else { Some (parse_quote ! (map (| b | b . unwrap () . freeze ()))) } , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bincode_interleaved < N2 : Location , Tag , CoreType > (self , other : & N2 ,) -> Stream < 'a , CoreType , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T , Out < CoreType > = (Tag , CoreType) > , CoreType : Serialize + DeserializeOwned , { self . send_bincode :: < N2 , CoreType > (other) . map (q ! (| (_ , b) | b)) } pub fn send_bytes_interleaved < N2 : Location , Tag > (self , other : & N2 ,) -> Stream < 'a , Bytes , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T , Out < Bytes > = (Tag , Bytes) > , { self . send_bytes :: < N2 > (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bincode < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < T > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) > , T : Clone + Serialize + DeserializeOwned , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bincode (other) } pub fn broadcast_bincode_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , T , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) , Out < T > = (Tag , T) > + 'a , T : Clone + Serialize + DeserializeOwned , { self . broadcast_bincode (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bytes < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) > + 'a , T : Clone , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bytes (other) } pub fn broadcast_bytes_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , Bytes , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) , Out < Bytes > = (Tag , Bytes) > + 'a , T : Clone , { self . broadcast_bytes (other) . map (q ! (| (_ , b) | b)) } } } pub use stream :: { Bounded , NoTick , Stream , Tick , Unbounded } ; pub mod singleton { pub use std :: cell :: RefCell ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use crate :: builder :: FlowLeaves ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial , CycleComplete } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: Stream ; pub use crate :: singleton :: CrossResult ; # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Singleton < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Singleton :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } pub use crate :: singleton :: Singleton ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Singleton { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleComplete < 'a > for Singleton < 'a , T , Bounded , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleCollectionWithInitial < 'a > for Singleton < 'a , T , Bounded , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , initial : Self , l : LocationId ,) -> Self { Singleton :: new (l , ir_leaves , HfPlusNode :: Union (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , }) , initial . ir_node . into_inner () . into () ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Singleton < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Singleton { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , U , W , C , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (Self :: other_ir_node (other)) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Singleton < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CrossSingleton (Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , Box :: new (HfPlusNode :: Unpersist (Box :: new (Self :: other_ir_node (other)))) ,))) ,) } } pub use crate :: singleton :: Optional ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Optional { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } pub fn some (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: new (singleton . location_kind , singleton . ir_leaves , singleton . ir_node . into_inner () ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > From < Singleton < 'a , T , W , C , N > > for Optional < 'a , T , W , C , N > { fn from (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: some (singleton) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Optional < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Optional { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn into_stream (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , Tick , N > > ,) -> Optional < 'a , (T , O) , Bounded , Tick , N > where O : Clone , { let other : Optional < 'a , O , Bounded , Tick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn union (self , other : Optional < 'a , T , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Optional < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_samples (self) -> Stream < 'a , T , Unbounded , NoTick , N > { self . latest_tick () . all_ticks () } pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . latest_tick () . continue_if (samples . first ()) . latest () . tick_samples () } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Unbounded , NoTick , N > > ,) -> Optional < 'a , (T , O) , Unbounded , NoTick , N > where O : Clone , { let other : Optional < 'a , O , Unbounded , NoTick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } self . latest_tick () . cross_singleton (other . latest_tick ()) . latest () } } } pub use singleton :: { Optional , Singleton } ; pub mod location { pub use std :: marker :: PhantomData ; pub use crate :: location :: LocationId ; pub use crate :: location :: Location ; pub use crate :: location :: Process ; # [cfg (stageleft_macro)] impl < P > Clone for Process < P > { fn clone (& self) -> Self { Process { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < P > Location for Process < P > { fn id (& self) -> LocationId { LocationId :: Process (self . id) } } pub use crate :: location :: Cluster ; # [cfg (stageleft_macro)] impl < C > Clone for Cluster < C > { fn clone (& self) -> Self { Cluster { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < C > Location for Cluster < C > { fn id (& self) -> LocationId { LocationId :: Cluster (self . id) } } pub use crate :: location :: CanSend ; # [cfg (stageleft_macro)] impl < P1 , P2 > CanSend < Process < P2 > > for Process < P1 > { type In < T > = T ; type Out < T > = T ; fn is_demux () -> bool { false } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < P1 , C2 > CanSend < Cluster < C2 > > for Process < P1 > { type In < T > = (u32 , T) ; type Out < T > = T ; fn is_demux () -> bool { true } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < C1 , P2 > CanSend < Process < P2 > > for Cluster < C1 > { type In < T > = T ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { false } fn is_tagged () -> bool { true } } # [cfg (stageleft_macro)] impl < C1 , C2 > CanSend < Cluster < C2 > > for Cluster < C1 > { type In < T > = (u32 , T) ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { true } fn is_tagged () -> bool { true } } } pub use location :: { Cluster , Process } ; pub mod deploy { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use stageleft :: Quoted ; pub mod graphs { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use super :: { LocalDeploy , Node , ProcessSpec } ; pub use crate :: deploy :: graphs :: SingleProcessGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for SingleProcessGraph { type Process = SingleNode ; type Cluster = SingleNode ; type Meta = () ; type GraphId = () ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { SingleNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { SingleNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , SingleProcessGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> SingleNode { SingleNode { } } } pub use crate :: deploy :: graphs :: SingleNode ; # [cfg (stageleft_macro)] impl Node for SingleNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } pub use crate :: deploy :: graphs :: MultiGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for MultiGraph { type Process = MultiNode ; type Cluster = MultiNode ; type Meta = () ; type GraphId = usize ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { MultiNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { MultiNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , MultiGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> MultiNode { MultiNode { } } } pub use crate :: deploy :: graphs :: MultiNode ; # [cfg (stageleft_macro)] impl Node for MultiNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } } pub use graphs :: * ; pub use crate :: deploy :: LocalDeploy ; pub use crate :: deploy :: Deploy ; # [cfg (stageleft_macro)] impl < 'a , T : Deploy < 'a , Process = N , Cluster = C , Meta = M , GraphId = R > , N : Node < Meta = M > , C : Node < Meta = M > , M : Default , R , > LocalDeploy < 'a > for T { type Process = N ; type Cluster = C ; type Meta = M ; type GraphId = R ; fn has_trivial_node () -> bool { < T as Deploy < 'a > > :: has_trivial_node () } fn trivial_process (id : usize) -> Self :: Process { < T as Deploy < 'a > > :: trivial_process (id) } fn trivial_cluster (id : usize) -> Self :: Cluster { < T as Deploy < 'a > > :: trivail_cluster (id) } } pub use crate :: deploy :: ProcessSpec ; pub use crate :: deploy :: ClusterSpec ; pub use crate :: deploy :: Node ; } pub use deploy :: { ClusterSpec , Deploy , ProcessSpec } ; pub mod cycle { pub use std :: marker :: PhantomData ; pub use crate :: builder :: FlowLeaves ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: cycle :: CycleComplete ; pub use crate :: cycle :: CycleCollection ; pub use crate :: cycle :: CycleCollectionWithInitial ; pub use crate :: cycle :: HfCycle ; # [cfg (stageleft_macro)] impl < 'a , S : CycleComplete < 'a > > HfCycle < 'a , S > { pub fn complete (self , stream : S) { let ident = self . ident ; S :: complete (stream , ident) } } } pub use cycle :: HfCycle ; pub mod builder { pub use std :: cell :: RefCell ; pub use std :: collections :: HashMap ; pub use std :: marker :: PhantomData ; pub use std :: rc :: Rc ; pub use std :: time :: Duration ; pub use hydroflow :: futures :: stream :: Stream as FuturesStream ; pub use hydroflow :: { tokio , tokio_stream } ; pub use internal :: TokenStream ; pub use proc_macro2 :: Span ; pub use quote :: quote ; pub use runtime_support :: FreeVariable ; pub use stageleft :: * ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Cluster , Location , LocationId , Process } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: { HfCycle , Optional , RuntimeContext , Singleton , Stream } ; pub mod built { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use hydroflow_lang :: graph :: { eliminate_extra_unions_tees , HydroflowGraph } ; pub use super :: deploy :: { DeployFlow , DeployResult } ; pub use crate :: deploy :: { ClusterSpec , Deploy , LocalDeploy , ProcessSpec } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Cluster , Process } ; pub use crate :: HfCompiled ; pub use crate :: builder :: built :: BuiltFlow ; # [cfg (stageleft_macro)] impl < 'a > Drop for BuiltFlow < 'a > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped BuiltFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn ir (& self) -> & Vec < HfPlusLeaf < 'a > > { & self . ir } pub fn optimize_with (mut self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> BuiltFlow < 'a > { self . used = true ; BuiltFlow { ir : f (std :: mem :: take (& mut self . ir)) , processes : std :: mem :: take (& mut self . processes) , clusters : std :: mem :: take (& mut self . clusters) , used : false , _phantom : PhantomData , } } } pub fn build_inner (ir : & mut Vec < HfPlusLeaf >) -> BTreeMap < usize , HydroflowGraph > { let mut builders = BTreeMap :: new () ; let mut built_tees = HashMap :: new () ; let mut next_stmt_id = 0 ; for leaf in ir { leaf . emit (& mut builders , & mut built_tees , & mut next_stmt_id) ; } builders . into_iter () . map (| (k , v) | { let (mut flat_graph , _ , _) = v . build () ; eliminate_extra_unions_tees (& mut flat_graph) ; (k , flat_graph) }) . collect () } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn compile_no_network < D : LocalDeploy < 'a > > (mut self) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; HfCompiled { hydroflow_ir : build_inner (& mut self . ir) , extra_stmts : BTreeMap :: new () , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> BuiltFlow < 'a > { self . optimize_with (crate :: persist_pullup :: persist_pullup) } fn into_deploy < D : LocalDeploy < 'a > > (mut self) -> DeployFlow < 'a , D > { self . used = true ; let processes = if D :: has_trivial_node () { self . processes . iter () . map (| id | (* id , D :: trivial_process (* id))) . collect () } else { HashMap :: new () } ; let clusters = if D :: has_trivial_node () { self . clusters . iter () . map (| id | (* id , D :: trivial_cluster (* id))) . collect () } else { HashMap :: new () } ; DeployFlow { ir : std :: mem :: take (& mut self . ir) , nodes : processes , clusters , used : false , _phantom : PhantomData , } } pub fn with_process < P , D : LocalDeploy < 'a > > (self , process : & Process < P > , spec : impl ProcessSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_process (process , spec) } pub fn with_cluster < C , D : LocalDeploy < 'a > > (self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_cluster (cluster , spec) } pub fn compile < D : Deploy < 'a > + 'a > (self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . into_deploy :: < D > () . compile (env) } pub fn deploy < D : Deploy < 'a , CompileEnv = () > + 'a > (self , env : & mut D :: InstantiateEnv ,) -> DeployResult < 'a , D > { self . into_deploy :: < D > () . deploy (env) } } } pub mod deploy { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use proc_macro2 :: Span ; pub use stageleft :: Quoted ; pub use super :: built :: build_inner ; pub use crate :: deploy :: { LocalDeploy , Node } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: { Cluster , ClusterSpec , Deploy , HfCompiled , Process , ProcessSpec } ; pub use crate :: builder :: deploy :: DeployFlow ; # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > Drop for DeployFlow < 'a , D > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped DeployFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > DeployFlow < 'a , D > { pub fn with_process < P > (mut self , process : & Process < P > , spec : impl ProcessSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < P > () . to_string () ; self . nodes . insert (process . id , spec . build (process . id , & tag_name)) ; self } pub fn with_cluster < C > (mut self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < C > () . to_string () ; self . clusters . insert (cluster . id , spec . build (cluster . id , & tag_name)) ; self } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployFlow < 'a , D > { pub fn compile (mut self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; let mut seen_tees : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | leaf . compile_network :: < D > (env , & mut seen_tees , & self . nodes , & self . clusters)) . collect () ; let extra_stmts = self . extra_stmts (env) ; HfCompiled { hydroflow_ir : build_inner (& mut ir_leaves_networked) , extra_stmts , _phantom : PhantomData , } } fn extra_stmts (& self , env : & < D as Deploy < 'a > > :: CompileEnv) -> BTreeMap < usize , Vec < syn :: Stmt > > { let all_locations_count = self . nodes . len () + self . clusters . len () ; let mut extra_stmts : BTreeMap < usize , Vec < syn :: Stmt > > = BTreeMap :: new () ; for & c_id in self . clusters . keys () { let self_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , c_id) , Span :: call_site () ,) ; let self_id_expr = D :: cluster_self_id (env) . splice () ; extra_stmts . entry (c_id) . or_default () . push (syn :: parse_quote ! { let # self_id_ident = # self_id_expr ; }) ; for other_location in 0 .. all_locations_count { let other_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , c_id) , Span :: call_site () ,) ; let other_id_expr = D :: cluster_ids (env , c_id) . splice () ; extra_stmts . entry (other_location) . or_default () . push (syn :: parse_quote ! { let # other_id_ident = # other_id_expr ; }) ; } } extra_stmts } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a , CompileEnv = () > > DeployFlow < 'a , D > { # [must_use] pub fn deploy (mut self , env : & mut D :: InstantiateEnv) -> DeployResult < 'a , D > { self . used = true ; let mut seen_tees_instantiate : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | { leaf . compile_network :: < D > (& () , & mut seen_tees_instantiate , & self . nodes , & self . clusters ,) }) . collect () ; let mut compiled = build_inner (& mut ir_leaves_networked) ; let mut extra_stmts = self . extra_stmts (& ()) ; let mut meta = D :: Meta :: default () ; let (mut processes , mut clusters) = (std :: mem :: take (& mut self . nodes) . into_iter () . map (| (node_id , node) | { node . instantiate (env , & mut meta , compiled . remove (& node_id) . unwrap () , extra_stmts . remove (& node_id) . unwrap_or_default () ,) ; (node_id , node) }) . collect :: < HashMap < _ , _ > > () , std :: mem :: take (& mut self . clusters) . into_iter () . map (| (cluster_id , cluster) | { cluster . instantiate (env , & mut meta , compiled . remove (& cluster_id) . unwrap () , extra_stmts . remove (& cluster_id) . unwrap_or_default () ,) ; (cluster_id , cluster) }) . collect :: < HashMap < _ , _ > > () ,) ; for node in processes . values_mut () { node . update_meta (& meta) ; } for cluster in clusters . values_mut () { cluster . update_meta (& meta) ; } let mut seen_tees_connect = HashMap :: new () ; for leaf in ir_leaves_networked { leaf . connect_network (& mut seen_tees_connect) ; } DeployResult { processes , clusters , } } } pub use crate :: builder :: deploy :: DeployResult ; # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployResult < 'a , D > { pub fn get_process < P > (& self , p : & Process < P >) -> & D :: Process { let id = match p . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . processes . get (& id) . unwrap () } pub fn get_cluster < C > (& self , c : & Cluster < C >) -> & D :: Cluster { let id = match c . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . clusters . get (& id) . unwrap () } } } # [doc = " Tracks the leaves of the dataflow IR. This is referenced by"] # [doc = " `Stream` and `HfCycle` to build the IR. The inner option will"] # [doc = " be set to `None` when this builder is finalized."] pub type FlowLeaves < 'a > = Rc < RefCell < Option < Vec < HfPlusLeaf < 'a > > > > > ; pub use crate :: builder :: ClusterIds ; # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Vec < u32 > > for ClusterIds < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , & 'a Vec < u32 > > for ClusterIds < 'a > { } # [derive (Copy , Clone)] pub struct ClusterSelfId < 'a > { pub id : usize , pub _phantom : PhantomData < & 'a mut & 'a u32 > , } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < u32 > for ClusterSelfId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , u32 > for ClusterSelfId < 'a > { } pub use crate :: builder :: FlowBuilder ; # [cfg (stageleft_macro)] impl < 'a > Drop for FlowBuilder < 'a > { fn drop (& mut self) { if ! self . finalized { panic ! ("Dropped FlowBuilder without finalizing, you may have forgotten to call `with_default_optimize`, `optimize_with`, or `finalize`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > QuotedContext for FlowBuilder < 'a > { fn create () -> Self { FlowBuilder :: new () } } # [cfg (stageleft_macro)] impl < 'a > FlowBuilder < 'a > { # [allow (clippy :: new_without_default)] pub fn new () -> FlowBuilder < 'a > { FlowBuilder { ir_leaves : Rc :: new (RefCell :: new (Some (Vec :: new ()))) , nodes : RefCell :: new (vec ! []) , clusters : RefCell :: new (vec ! []) , cycle_ids : RefCell :: new (HashMap :: new ()) , next_node_id : RefCell :: new (0) , finalized : false , _phantom : PhantomData , } } pub fn finalize (mut self) -> built :: BuiltFlow < 'a > { self . finalized = true ; built :: BuiltFlow { ir : self . ir_leaves . borrow_mut () . take () . unwrap () , processes : self . nodes . replace (vec ! []) , clusters : self . clusters . replace (vec ! []) , used : false , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> built :: BuiltFlow < 'a > { self . finalize () . with_default_optimize () } pub fn optimize_with (self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> built :: BuiltFlow < 'a > { self . finalize () . optimize_with (f) } pub fn ir_leaves (& self) -> & FlowLeaves < 'a > { & self . ir_leaves } pub fn process < P > (& self) -> Process < P > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . nodes . borrow_mut () . push (id) ; Process { id , _phantom : PhantomData , } } pub fn cluster < C > (& self) -> Cluster < C > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . clusters . borrow_mut () . push (id) ; Cluster { id , _phantom : PhantomData , } } pub fn runtime_context (& self) -> RuntimeContext < 'a > { RuntimeContext { _phantom : PhantomData , } } pub fn cluster_members < C > (& self , cluster : & Cluster < C > ,) -> impl Quoted < 'a , & 'a Vec < u32 > > + Copy + 'a { ClusterIds { id : cluster . id , _phantom : PhantomData , } } pub fn cluster_self_id < C > (& self , cluster : & Cluster < C >) -> impl Quoted < 'a , u32 > + Copy + 'a { ClusterSelfId { id : cluster . id , _phantom : PhantomData , } } pub fn spin < L : Location > (& self , on : & L) -> Stream < 'a , () , Unbounded , NoTick , L > { Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Spin () , location_kind : on . id () , })) ,) } pub fn spin_batch < L : Location > (& self , on : & L , batch_size : impl Quoted < 'a , usize > + Copy + 'a ,) -> Stream < 'a , () , Bounded , Tick , L > { self . spin (on) . flat_map (q ! (move | _ | 0 .. batch_size)) . map (q ! (| _ | ())) . tick_batch () } pub fn source_stream < T , E : FuturesStream < Item = T > + Unpin , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Unbounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Stream (e . into ()) , location_kind : on . id () , })) ,) } pub fn source_iter < T , E : IntoIterator < Item = T > , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Bounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , })) ,) } pub fn singleton < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Singleton < 'a , T , Bounded , NoTick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Singleton :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,)))) ,) } pub fn singleton_first_tick < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Optional < 'a , T , Bounded , Tick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,) } pub fn source_interval < L : Location > (& self , on : & L , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , () , Unbounded , NoTick , L > { let interval = interval . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : on . id () , })) ,) } pub fn source_interval_delayed < L : Location > (& self , on : & L , delay : impl Quoted < 'a , Duration > + Copy + 'a , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , tokio :: time :: Instant , Unbounded , NoTick , L > { self . source_stream (on , q ! (tokio_stream :: wrappers :: IntervalStream :: new (tokio :: time :: interval_at (tokio :: time :: Instant :: now () + delay , interval))) ,) . tick_batch () . first () . latest () } pub fn cycle < S : CycleCollection < 'a > > (& self , on : & S :: Location) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , on . id ()) ,) } pub fn cycle_with_initial < S : CycleCollectionWithInitial < 'a > > (& self , on : & S :: Location , initial : S ,) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , initial , on . id ()) ,) } } } pub use builder :: FlowBuilder ; pub mod ir { pub use core :: panic ; pub use std :: cell :: RefCell ; pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow_lang :: graph :: FlatGraphBuilder ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: ToTokens ; pub use syn :: parse_quote ; pub use crate :: deploy :: Deploy ; pub use crate :: location :: LocationId ; pub use crate :: ir :: DebugExpr ; # [cfg (stageleft_macro)] impl From < syn :: Expr > for DebugExpr { fn from (expr : syn :: Expr) -> DebugExpr { DebugExpr (expr) } } # [cfg (stageleft_macro)] impl Deref for DebugExpr { type Target = syn :: Expr ; fn deref (& self) -> & Self :: Target { & self . 0 } } # [cfg (stageleft_macro)] impl ToTokens for DebugExpr { fn to_tokens (& self , tokens : & mut TokenStream) { self . 0 . to_tokens (tokens) ; } } # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugExpr { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "{}" , self . 0 . to_token_stream ()) } } pub use crate :: ir :: DebugInstantiate ; # [cfg (stageleft_macro)] impl < 'a > std :: fmt :: Debug for DebugInstantiate < 'a > { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<network instantiate>") } } pub use crate :: ir :: DebugPipelineFn ; # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugPipelineFn { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<function>") } } pub use crate :: ir :: HfPlusSource ; pub use crate :: ir :: HfPlusLeaf ; # [cfg (stageleft_macro)] impl < 'a > HfPlusLeaf < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . compile_network :: < D > (compile_env , s , nodes , clusters) ; } , seen_tees ,) } pub fn connect_network (self , seen_tees : & mut SeenTees < 'a >) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . connect_network (s) ; } , seen_tees ,) } pub fn transform_children (self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) -> HfPlusLeaf < 'a > { match self { HfPlusLeaf :: ForEach { f , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: ForEach { f , input } } HfPlusLeaf :: DestSink { sink , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: DestSink { sink , input } } HfPlusLeaf :: CycleSink { ident , location_kind , mut input , } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: CycleSink { ident , location_kind , input , } } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) { match self { HfPlusLeaf :: ForEach { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> for_each (# f) ; }) ; } HfPlusLeaf :: DestSink { sink , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink) ; }) ; } HfPlusLeaf :: CycleSink { ident , location_kind , input , } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; assert_eq ! (input_location_id , * location_id , "cycle_sink location mismatch") ; graph_builders . entry (* location_id) . or_default () . add_statement (parse_quote ! { # ident = # input_ident ; }) ; } } } } pub use crate :: ir :: HfPlusNode ; pub type SeenTees < 'a > = HashMap < * const RefCell < HfPlusNode < 'a > > , Rc < RefCell < HfPlusNode < 'a > > > > ; # [cfg (stageleft_macro)] impl < 'a > HfPlusNode < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (& mut self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) { self . transform_children (| n , s | n . compile_network :: < D > (compile_env , s , nodes , clusters) , seen_tees ,) ; if let HfPlusNode :: Network { from_location , to_location , instantiate_fn , .. } = self { let (sink_expr , source_expr , connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { let ((sink , source) , connect_fn) = match (from_location , to_location) { (LocationId :: Process (from) , LocationId :: Process (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: o2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Process (from) , LocationId :: Cluster (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: o2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Process (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: m2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Cluster (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: m2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } } ; (sink , source , connect_fn) } DebugInstantiate :: Finalized (_ , _ , _) => panic ! ("network already finalized") , } ; * instantiate_fn = DebugInstantiate :: Finalized (sink_expr , source_expr , connect_fn) ; } } pub fn connect_network (& mut self , seen_tees : & mut SeenTees < 'a >) { self . transform_children (| n , s | n . connect_network (s) , seen_tees) ; if let HfPlusNode :: Network { instantiate_fn , .. } = self { match instantiate_fn { DebugInstantiate :: Building () => panic ! ("network not built") , DebugInstantiate :: Finalized (_ , _ , ref connect_fn) => { connect_fn () ; } } } } pub fn transform_children (& mut self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) { match self { HfPlusNode :: Placeholder => { panic ! () ; } HfPlusNode :: Source { .. } => { } HfPlusNode :: CycleSource { .. } => { } HfPlusNode :: Tee { inner } => { if let Some (transformed) = seen_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { * inner = transformed . clone () ; } else { let transformed_cell = Rc :: new (RefCell :: new (HfPlusNode :: Placeholder)) ; seen_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , transformed_cell . clone () ,) ; let mut orig = inner . replace (HfPlusNode :: Placeholder) ; transform (& mut orig , seen_tees) ; * transformed_cell . borrow_mut () = orig ; * inner = transformed_cell ; } } HfPlusNode :: Persist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Unpersist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Delta (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Union (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossProduct (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossSingleton (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Join (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Difference (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: AntiJoin (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Map { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FlatMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Filter { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FilterMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Sort (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: DeferTick (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Enumerate (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Inspect { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Unique (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Fold { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FoldKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Reduce { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: ReduceKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Network { input , .. } => { transform (input . as_mut () , seen_tees) ; } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) -> (syn :: Ident , usize) { match self { HfPlusNode :: Placeholder => { panic ! () } HfPlusNode :: Persist (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let persist_id = * next_stmt_id ; * next_stmt_id += 1 ; let persist_ident = syn :: Ident :: new (& format ! ("stream_{}" , persist_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # persist_ident = # inner_ident -> persist ::<'static > () ; }) ; (persist_ident , location) } HfPlusNode :: Unpersist (_) => { panic ! ("Unpersist is a marker node and should have been optimized away. This is likely a compiler bug.") } HfPlusNode :: Delta (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let delta_id = * next_stmt_id ; * next_stmt_id += 1 ; let delta_ident = syn :: Ident :: new (& format ! ("stream_{}" , delta_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # delta_ident = # inner_ident -> multiset_delta () ; }) ; (delta_ident , location) } HfPlusNode :: Source { source , location_kind , } => { let source_id = * next_stmt_id ; * next_stmt_id += 1 ; let source_ident = syn :: Ident :: new (& format ! ("stream_{}" , source_id) , Span :: call_site ()) ; let source_stmt = match source { HfPlusSource :: Stream (expr) => { parse_quote ! { # source_ident = source_stream (# expr) ; } } HfPlusSource :: Iter (expr) => { parse_quote ! { # source_ident = source_iter (# expr) ; } } HfPlusSource :: Interval (expr) => { parse_quote ! { # source_ident = source_interval (# expr) ; } } HfPlusSource :: Spin () => { parse_quote ! { # source_ident = spin () ; } } } ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; graph_builders . entry (* location_id) . or_default () . add_statement (source_stmt) ; (source_ident , * location_id) } HfPlusNode :: CycleSource { ident , location_kind , } => { let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; (ident . clone () , * location_id) } HfPlusNode :: Tee { inner } => { if let Some (ret) = built_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { ret . clone () } else { let (inner_ident , inner_location_id) = inner . borrow () . emit (graph_builders , built_tees , next_stmt_id) ; let tee_id = * next_stmt_id ; * next_stmt_id += 1 ; let tee_ident = syn :: Ident :: new (& format ! ("stream_{}" , tee_id) , Span :: call_site ()) ; let builder = graph_builders . entry (inner_location_id) . or_default () ; builder . add_statement (parse_quote ! { # tee_ident = # inner_ident -> tee () ; }) ; built_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , (tee_ident . clone () , inner_location_id) ,) ; (tee_ident , inner_location_id) } } HfPlusNode :: Union (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "union inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let union_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # union_ident = union () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [0] # union_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # union_ident ; }) ; (union_ident , left_location_id) } HfPlusNode :: CrossSingleton (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "cross_singleton inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let cross_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # cross_ident = cross_singleton () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [input] # cross_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [single] # cross_ident ; }) ; (cross_ident , left_location_id) } HfPlusNode :: CrossProduct (..) | HfPlusNode :: Join (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: CrossProduct (..)) { parse_quote ! (cross_join_multiset) } else { parse_quote ! (join_multiset) } ; let (HfPlusNode :: CrossProduct (left , right) | HfPlusNode :: Join (left , right)) = self else { unreachable ! () } ; let (left_inner , left_was_persist) = if let HfPlusNode :: Persist (left) = left . as_ref () { (left , true) } else { (left , false) } ; let (right_inner , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left_inner . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right_inner . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "join / cross product inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; match (left_was_persist , right_was_persist) { (true , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'static > () ; }) ; } (true , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'tick > () ; }) ; } (false , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } (false , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } } ; builder . add_statement (parse_quote ! { # left_ident -> [0] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Difference (..) | HfPlusNode :: AntiJoin (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Difference (..)) { parse_quote ! (difference_multiset) } else { parse_quote ! (anti_join_multiset) } ; let (HfPlusNode :: Difference (left , right) | HfPlusNode :: AntiJoin (left , right)) = self else { unreachable ! () } ; let (right , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "difference / anti join inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; if right_was_persist { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } else { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } builder . add_statement (parse_quote ! { # left_ident -> [pos] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [neg] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Map { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let map_id = * next_stmt_id ; * next_stmt_id += 1 ; let map_ident = syn :: Ident :: new (& format ! ("stream_{}" , map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # map_ident = # input_ident -> map (# f) ; }) ; (map_ident , input_location_id) } HfPlusNode :: FlatMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let flat_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let flat_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , flat_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # flat_map_ident = # input_ident -> flat_map (# f) ; }) ; (flat_map_ident , input_location_id) } HfPlusNode :: Filter { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_ident = # input_ident -> filter (# f) ; }) ; (filter_ident , input_location_id) } HfPlusNode :: FilterMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_map_ident = # input_ident -> filter_map (# f) ; }) ; (filter_map_ident , input_location_id) } HfPlusNode :: Sort (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sort_id = * next_stmt_id ; * next_stmt_id += 1 ; let sort_ident = syn :: Ident :: new (& format ! ("stream_{}" , sort_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # sort_ident = # input_ident -> sort () ; }) ; (sort_ident , input_location_id) } HfPlusNode :: DeferTick (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let defer_tick_id = * next_stmt_id ; * next_stmt_id += 1 ; let defer_tick_ident = syn :: Ident :: new (& format ! ("stream_{}" , defer_tick_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # defer_tick_ident = # input_ident -> defer_tick_lazy () ; }) ; (defer_tick_ident , input_location_id) } HfPlusNode :: Enumerate (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let enumerate_id = * next_stmt_id ; * next_stmt_id += 1 ; let enumerate_ident = syn :: Ident :: new (& format ! ("stream_{}" , enumerate_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # enumerate_ident = # input_ident -> enumerate () ; }) ; (enumerate_ident , input_location_id) } HfPlusNode :: Inspect { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let inspect_id = * next_stmt_id ; * next_stmt_id += 1 ; let inspect_ident = syn :: Ident :: new (& format ! ("stream_{}" , inspect_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # inspect_ident = # input_ident -> inspect (# f) ; }) ; (inspect_ident , input_location_id) } HfPlusNode :: Unique (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let unique_id = * next_stmt_id ; * next_stmt_id += 1 ; let unique_ident = syn :: Ident :: new (& format ! ("stream_{}" , unique_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # unique_ident = # input_ident -> unique ::<'tick > () ; }) ; (unique_ident , input_location_id) } HfPlusNode :: Fold { .. } | HfPlusNode :: FoldKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Fold { .. }) { parse_quote ! (fold) } else { parse_quote ! (fold_keyed) } ; let (HfPlusNode :: Fold { init , acc , input } | HfPlusNode :: FoldKeyed { init , acc , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let fold_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'static > (# init , # acc) ; }) ; } else { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'tick > (# init , # acc) ; }) ; } (fold_ident , input_location_id) } HfPlusNode :: Reduce { .. } | HfPlusNode :: ReduceKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Reduce { .. }) { parse_quote ! (reduce) } else { parse_quote ! (reduce_keyed) } ; let (HfPlusNode :: Reduce { f , input } | HfPlusNode :: ReduceKeyed { f , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let reduce_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'static > (# f) ; }) ; } else { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'tick > (# f) ; }) ; } (reduce_ident , input_location_id) } HfPlusNode :: Network { from_location : _ , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input , } => { let (sink_expr , source_expr , _connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { panic ! ("Expected the network to be finalized") } DebugInstantiate :: Finalized (sink , source , connect_fn) => { (sink , source , connect_fn) } } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sender_builder = graph_builders . entry (input_location_id) . or_default () ; if let Some (serialize_pipeline) = serialize_pipeline { sender_builder . add_statement (parse_quote ! { # input_ident -> # serialize_pipeline -> dest_sink (# sink_expr) ; }) ; } else { sender_builder . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink_expr) ; }) ; } let to_id = match to_location { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let receiver_builder = graph_builders . entry (* to_id) . or_default () ; let receiver_stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let receiver_stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , receiver_stream_id) , Span :: call_site ()) ; if let Some (deserialize_pipeline) = deserialize_pipeline { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) -> # deserialize_pipeline ; }) ; } else { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) ; }) ; } (receiver_stream_ident , * to_id) } } } } } pub mod persist_pullup { pub use std :: cell :: RefCell ; pub use std :: collections :: HashSet ; pub use std :: ops :: Deref ; pub use crate :: ir :: * ; pub fn persist_pullup_node < 'a > (node : & mut HfPlusNode < 'a > , seen_tees : & mut SeenTees < 'a > , persist_pulled_tees : & mut HashSet < * const RefCell < HfPlusNode < 'a > > > ,) { node . transform_children (| n , s | persist_pullup_node (n , s , persist_pulled_tees) , seen_tees ,) ; match node { HfPlusNode :: Unpersist (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Unpersist (deref!(HfPlusNode :: Persist (box behind_persist))) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Delta (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Delta (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Tee { inner } => { if persist_pulled_tees . contains (& (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >)) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } else { let inner_borrow = inner . borrow () ; if let HfPlusNode :: Persist (_) = inner_borrow . deref () { drop (inner_borrow) ; persist_pulled_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >) ; if let HfPlusNode :: Persist (box behind_persist) = inner . replace (HfPlusNode :: Placeholder) { * inner . borrow_mut () = behind_persist ; } else { unreachable ! () } * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } } } HfPlusNode :: Map { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Map { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Map { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: FlatMap { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: FlatMap { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: FlatMap { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Filter { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Filter { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Filter { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Network { input : box HfPlusNode :: Persist (_) , .. } => { if let HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Union (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Union (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Union (left , right))) ; } else { unreachable ! () } } HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: CrossProduct (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,) ,)))) ; } else { unreachable ! () } } HfPlusNode :: Join (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Join (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: Join (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,))))) ; } else { unreachable ! () } } _ => { } } } pub fn persist_pullup (ir : Vec < HfPlusLeaf >) -> Vec < HfPlusLeaf > { let mut seen_tees = Default :: default () ; let mut persist_pulled_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| n , s | persist_pullup_node (n , s , & mut persist_pulled_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn persist_pullup_through_map () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } # [test] fn persist_pullup_behind_tee () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; let before_tee = flow . source_iter (& process , q ! (0 .. 10)) . tick_batch () . persist () ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } } } pub mod profiler { pub use std :: cell :: RefCell ; pub use hydroflow :: futures :: channel :: mpsc :: UnboundedSender ; pub use stageleft :: * ; pub use crate as hydroflow_plus ; pub use crate :: ir :: * ; pub use crate :: RuntimeContext ; pub fn increment_counter (count : & mut u64) { * count += 1 ; } pub fn quoted_any_fn < 'a , F : Fn (& usize) + 'a , Q : IntoQuotedMut < 'a , F > > (q : Q) -> Q { q } # [doc = " Add a profiling node before each node to count the cardinality of its input"] pub fn add_profiling_node < 'a > (node : & mut HfPlusNode < 'a > , _context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > , id : & mut u32 , seen_tees : & mut SeenTees < 'a > ,) { let my_id = * id ; * id += 1 ; node . transform_children (| node , seen_tees | { add_profiling_node (node , _context , counters , counter_queue , id , seen_tees) } , seen_tees ,) ; let orig_node = std :: mem :: replace (node , HfPlusNode :: Placeholder) ; * node = HfPlusNode :: Inspect { f : quoted_any_fn (q ! ({ counter_queue . borrow () . unbounded_send ((my_id as usize , counters . borrow () [my_id as usize])) . unwrap () ; counters . borrow_mut () [my_id as usize] = 0 ; move | _ | { hydroflow_plus :: profiler :: increment_counter (& mut counters . borrow_mut () [my_id as usize] ,) ; } })) . splice () . into () , input : Box :: new (orig_node) , } } # [doc = " Count the cardinality of each input and periodically output to a file"] pub fn profiling < 'a > (ir : Vec < HfPlusLeaf < 'a > > , context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > ,) -> Vec < HfPlusLeaf < 'a > > { let mut id = 0 ; let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | { add_profiling_node (node , context , counters , counter_queue , & mut id , seen_tees) } , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn profiler_wrapping_all_operators () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let runtime_context = flow . runtime_context () ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (& built . ir ()) ; let counters = RuntimeData :: new ("Fake") ; let counter_queue = RuntimeData :: new ("Fake") ; let pushed_down = built . with_default_optimize () . optimize_with (| ir | super :: profiling (ir , runtime_context , counters , counter_queue)) ; insta :: assert_debug_snapshot ! (& pushed_down . ir ()) ; let _ = pushed_down . compile_no_network :: < MultiGraph > () ; } } } pub mod properties { pub use std :: collections :: HashSet ; pub use stageleft :: * ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , SeenTees } ; pub use crate :: properties :: PropertyDatabase ; # [doc = " Allows us to convert the hydroflow datatype for folds to a binary operation for the algebra"] # [doc = " property tests."] # [allow (dead_code)] pub fn convert_hf_to_binary < I , A : Default , F : Fn (& mut A , I) > (f : F) -> impl Fn (I , I) -> A { move | a , b | { let mut acc = Default :: default () ; f (& mut acc , a) ; f (& mut acc , b) ; acc } } # [cfg (stageleft_macro)] impl PropertyDatabase { # [doc = " Tags the expression as commutative."] pub fn add_commutative_tag < 'a , I , A , F : Fn (& mut A , I) , Q : Quoted < 'a , F > + Clone > (& mut self , expr : Q ,) -> Q { let expr_clone = expr . clone () ; self . commutative . insert (expr_clone . splice ()) ; expr } pub fn is_tagged_commutative (& self , expr : & syn :: Expr) -> bool { self . commutative . contains (expr) } } pub fn properties_optimize_node < 'a > (node : & mut HfPlusNode < 'a > , db : & PropertyDatabase , seen_tees : & mut SeenTees < 'a > ,) { node . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , seen_tees ,) ; match node { HfPlusNode :: ReduceKeyed { f , .. } if db . is_tagged_commutative (& f . 0) => { dbg ! ("IDENTIFIED COMMUTATIVE OPTIMIZATION for {:?}" , & f) ; } _ => { } } } pub fn properties_optimize < 'a > (ir : Vec < HfPlusLeaf < 'a > > , db : & PropertyDatabase ,) -> Vec < HfPlusLeaf < 'a > > { let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use super :: * ; use crate :: deploy :: SingleProcessGraph ; use crate :: FlowBuilder ; # [test] fn test_property_database () { let mut db = PropertyDatabase :: default () ; assert ! (! db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; let _ = db . add_commutative_tag (q ! (| a : & mut i32 , b : i32 | * a += b)) ; assert ! (db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; } # [test] fn test_property_optimized () { let flow = FlowBuilder :: new () ; let mut database = PropertyDatabase :: default () ; let process = flow . process :: < () > () ; let counter_func = q ! (| count : & mut i32 , _ | * count += 1) ; let _ = database . add_commutative_tag (counter_func) ; flow . source_iter (& process , q ! (vec ! [])) . map (q ! (| string : String | (string , ()))) . tick_batch () . fold_keyed (q ! (|| 0) , counter_func) . all_ticks () . for_each (q ! (| (string , count) | println ! ("{}: {}" , string , count))) ; let built = flow . finalize () . optimize_with (| ir | properties_optimize (ir , & database)) . with_default_optimize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let _ = built . compile_no_network :: < SingleProcessGraph > () ; } } } pub use crate :: RuntimeContext ; # [cfg (stageleft_macro)] impl Copy for RuntimeContext < '_ > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Context > for RuntimeContext < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (quote ! (& context))) } } pub use crate :: HfCompiled ; # [cfg (stageleft_macro)] impl < 'a , ID > HfCompiled < 'a , ID > { pub fn hydroflow_ir (& self) -> & BTreeMap < usize , HydroflowGraph > { & self . hydroflow_ir } } # [cfg (stageleft_macro)] impl < 'a > HfCompiled < 'a , usize > { pub fn with_dynamic_id (self , id : impl Quoted < 'a , usize >) -> HfBuiltWithId < 'a > { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; let mut conditioned_tokens = None ; for (subgraph_id , flat_graph) in self . hydroflow_ir { let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; let my_extra_stmts = self . extra_stmts . get (& subgraph_id) . cloned () . unwrap_or_default () ; if let Some (conditioned_tokens) = conditioned_tokens . as_mut () { * conditioned_tokens = syn :: parse_quote ! { # conditioned_tokens else if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } } ; } else { conditioned_tokens = Some (syn :: parse_quote ! { if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } }) ; } } let conditioned_tokens : TokenStream = conditioned_tokens . unwrap () ; let id = id . splice () ; HfBuiltWithId { tokens : syn :: parse_quote ! ({ let __given_id = # id ; # conditioned_tokens else { panic ! ("Invalid node id: {}" , __given_id) ; } }) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfCompiled < 'a , () > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfCompiled < 'a , () > { fn to_tokens (mut self) -> (Option < TokenStream > , Option < TokenStream >) { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; if self . hydroflow_ir . len () != 1 { panic ! ("Expected exactly one subgraph in the Hydroflow IR") ; } let flat_graph = self . hydroflow_ir . remove (& 0) . unwrap () ; let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; (None , Some (tokens)) } } pub use crate :: HfBuiltWithId ; # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfBuiltWithId < 'a > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfBuiltWithId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (self . tokens)) } }
[INFO] [stdout]   |
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] error: `box` patterns have been removed (feature `box_patterns`)
[INFO] [stdout]  --> /opt/rustwide/target/debug/build/hydroflow_plus/5672655b657d1e44/out/lib_pub.rs:1:92037
[INFO] [stdout]   |
[INFO] [stdout] 1 | ...d_persist ; } else { unreachable ! () } } HfPlusNode :: Delta (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Delta (box...
[INFO] [stdout]   |                                                                   ^^^
[INFO] [stdout]   |
[INFO] [stdout]   = help: enable feature `deref_patterns` instead and...
[INFO] [stdout] help: ...if possible just remove keyword `box`...
[INFO] [stdout]   |
[INFO] [stdout] 1 - pub use std :: collections :: BTreeMap ; pub use std :: marker :: PhantomData ; pub use hydroflow :: scheduled :: context :: Context ; pub use hydroflow :: scheduled :: graph :: Hydroflow ; pub use hydroflow :: * ; pub use lang :: graph :: { partition_graph , HydroflowGraph } ; pub use proc_macro2 :: TokenStream ; pub use quote :: quote ; pub use stageleft :: runtime_support :: FreeVariable ; pub use stageleft :: Quoted ; pub mod runtime_support { pub use bincode ; } pub mod stream { pub use std :: cell :: RefCell ; pub use std :: hash :: Hash ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow :: bytes :: Bytes ; pub use hydroflow :: futures :: Sink ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: quote ; pub use serde :: de :: DeserializeOwned ; pub use serde :: Serialize ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use syn :: parse_quote ; pub use crate :: builder :: { ClusterIds , FlowLeaves } ; pub use crate :: cycle :: { CycleCollection , CycleComplete } ; pub use crate :: ir :: { DebugInstantiate , HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { CanSend , Location , LocationId } ; pub use crate :: { Cluster , Optional , Singleton } ; pub use crate :: stream :: Unbounded ; pub use crate :: stream :: Bounded ; pub use crate :: stream :: NoTick ; pub use crate :: stream :: Tick ; pub use crate :: stream :: Stream ; # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Stream { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Stream < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Stream { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , C , N > > ,) -> Stream < 'a , (T , O) , W , C , N > where O : Clone , { let other : Optional < 'a , O , Bounded , C , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn cross_product < O > (self , other : Stream < 'a , O , W , C , N >) -> Stream < 'a , (T , O) , W , C , N > where T : Clone , O : Clone , { if self . location_kind != other . location_kind { panic ! ("cross_product must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossProduct (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn union (self , other : Stream < 'a , T , W , C , N >) -> Stream < 'a , T , W , C , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn dest_sink < S : Unpin + Sink < T > + 'a > (self , sink : impl Quoted < 'a , S >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: DestSink { sink : sink . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn first (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } # [doc = " Allow this stream through if the other stream has elements, otherwise the output is empty."] pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } # [doc = " Allow this stream through if the other stream is empty, otherwise the output is empty."] pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn enumerate (self) -> Stream < 'a , (usize , T) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Enumerate (Box :: new (self . ir_node . into_inner ())) ,) } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn sort (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Ord , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Sort (Box :: new (self . ir_node . into_inner ())) ,) } pub fn count (self) -> Singleton < 'a , usize , Bounded , Tick , N > { self . fold (q ! (|| 0usize) , q ! (| count , _ | * count += 1)) } pub fn delta (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } pub fn unique (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Eq + Hash , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unique (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn tick_batch (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_prefix (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { self . tick_batch () . persist () } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn for_each < F : Fn (T) + 'a > (self , f : impl IntoQuotedMut < 'a , F >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: ForEach { input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , f : f . splice () . into () , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Unbounded , NoTick , N > { pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . tick_batch () . continue_if (samples . first ()) . all_ticks () } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Unbounded , NoTick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , C , N : Location > Stream < 'a , T , Bounded , C , N > { pub fn filter_not_in (self , other : Stream < 'a , T , Bounded , C , N >) -> Stream < 'a , T , Bounded , C , N > where T : Eq + Hash , { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Difference (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Stream < 'a , & T , W , C , N > { pub fn cloned (self) -> Stream < 'a , T , W , C , N > { self . map (q ! (| d | d . clone ())) } } # [cfg (stageleft_macro)] impl < 'a , K , V1 , W , C , N : Location > Stream < 'a , (K , V1) , W , C , N > { pub fn join < W2 , V2 > (self , n : Stream < 'a , (K , V2) , W2 , C , N > ,) -> Stream < 'a , (K , (V1 , V2)) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Join (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } pub fn anti_join < W2 > (self , n : Stream < 'a , K , W2 , C , N >) -> Stream < 'a , (K , V1) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("anti_join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: AntiJoin (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , K : Eq + Hash , V , N : Location > Stream < 'a , (K , V) , Bounded , Tick , N > { pub fn fold_keyed < A , I : Fn () -> A + 'a , F : Fn (& mut A , V) + 'a > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , A) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FoldKeyed { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce_keyed < F : Fn (& mut V , V) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , V) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: ReduceKeyed { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } pub fn get_this_crate () -> TokenStream { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , Span :: call_site ()) ; quote ! { # ident } } } } pub fn serialize_bincode < T : Serialize > (is_demux : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if is_demux { parse_quote ! { map (| (id , data) | { (id , # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into ()) }) } } else { parse_quote ! { map (| data | { # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into () }) } } } pub fn deserialize_bincode < T : DeserializeOwned > (tagged : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if tagged { parse_quote ! { map (| res | { let (id , b) = res . unwrap () ; (id , # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& b) . unwrap ()) }) } } else { parse_quote ! { map (| res | { # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& res . unwrap ()) . unwrap () }) } } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn send_bincode < N2 : Location , CoreType > (self , other : & N2 ,) -> Stream < 'a , N :: Out < CoreType > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T > , CoreType : Serialize + DeserializeOwned , { let serialize_pipeline = Some (serialize_bincode :: < CoreType > (N :: is_demux ())) ; let deserialize_pipeline = Some (deserialize_bincode :: < CoreType > (N :: is_tagged ())) ; Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bytes < N2 : Location > (self , other : & N2 ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T > , { Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline : None , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline : if N :: is_tagged () { Some (parse_quote ! (map (| (id , b) | (id , b . unwrap () . freeze ())))) } else { Some (parse_quote ! (map (| b | b . unwrap () . freeze ()))) } , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bincode_interleaved < N2 : Location , Tag , CoreType > (self , other : & N2 ,) -> Stream < 'a , CoreType , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T , Out < CoreType > = (Tag , CoreType) > , CoreType : Serialize + DeserializeOwned , { self . send_bincode :: < N2 , CoreType > (other) . map (q ! (| (_ , b) | b)) } pub fn send_bytes_interleaved < N2 : Location , Tag > (self , other : & N2 ,) -> Stream < 'a , Bytes , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T , Out < Bytes > = (Tag , Bytes) > , { self . send_bytes :: < N2 > (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bincode < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < T > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) > , T : Clone + Serialize + DeserializeOwned , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bincode (other) } pub fn broadcast_bincode_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , T , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) , Out < T > = (Tag , T) > + 'a , T : Clone + Serialize + DeserializeOwned , { self . broadcast_bincode (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bytes < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) > + 'a , T : Clone , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bytes (other) } pub fn broadcast_bytes_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , Bytes , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) , Out < Bytes > = (Tag , Bytes) > + 'a , T : Clone , { self . broadcast_bytes (other) . map (q ! (| (_ , b) | b)) } } } pub use stream :: { Bounded , NoTick , Stream , Tick , Unbounded } ; pub mod singleton { pub use std :: cell :: RefCell ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use crate :: builder :: FlowLeaves ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial , CycleComplete } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: Stream ; pub use crate :: singleton :: CrossResult ; # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Singleton < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Singleton :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } pub use crate :: singleton :: Singleton ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Singleton { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleComplete < 'a > for Singleton < 'a , T , Bounded , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleCollectionWithInitial < 'a > for Singleton < 'a , T , Bounded , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , initial : Self , l : LocationId ,) -> Self { Singleton :: new (l , ir_leaves , HfPlusNode :: Union (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , }) , initial . ir_node . into_inner () . into () ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Singleton < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Singleton { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , U , W , C , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (Self :: other_ir_node (other)) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Singleton < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CrossSingleton (Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , Box :: new (HfPlusNode :: Unpersist (Box :: new (Self :: other_ir_node (other)))) ,))) ,) } } pub use crate :: singleton :: Optional ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Optional { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } pub fn some (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: new (singleton . location_kind , singleton . ir_leaves , singleton . ir_node . into_inner () ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > From < Singleton < 'a , T , W , C , N > > for Optional < 'a , T , W , C , N > { fn from (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: some (singleton) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Optional < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Optional { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn into_stream (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , Tick , N > > ,) -> Optional < 'a , (T , O) , Bounded , Tick , N > where O : Clone , { let other : Optional < 'a , O , Bounded , Tick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn union (self , other : Optional < 'a , T , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Optional < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_samples (self) -> Stream < 'a , T , Unbounded , NoTick , N > { self . latest_tick () . all_ticks () } pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . latest_tick () . continue_if (samples . first ()) . latest () . tick_samples () } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Unbounded , NoTick , N > > ,) -> Optional < 'a , (T , O) , Unbounded , NoTick , N > where O : Clone , { let other : Optional < 'a , O , Unbounded , NoTick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } self . latest_tick () . cross_singleton (other . latest_tick ()) . latest () } } } pub use singleton :: { Optional , Singleton } ; pub mod location { pub use std :: marker :: PhantomData ; pub use crate :: location :: LocationId ; pub use crate :: location :: Location ; pub use crate :: location :: Process ; # [cfg (stageleft_macro)] impl < P > Clone for Process < P > { fn clone (& self) -> Self { Process { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < P > Location for Process < P > { fn id (& self) -> LocationId { LocationId :: Process (self . id) } } pub use crate :: location :: Cluster ; # [cfg (stageleft_macro)] impl < C > Clone for Cluster < C > { fn clone (& self) -> Self { Cluster { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < C > Location for Cluster < C > { fn id (& self) -> LocationId { LocationId :: Cluster (self . id) } } pub use crate :: location :: CanSend ; # [cfg (stageleft_macro)] impl < P1 , P2 > CanSend < Process < P2 > > for Process < P1 > { type In < T > = T ; type Out < T > = T ; fn is_demux () -> bool { false } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < P1 , C2 > CanSend < Cluster < C2 > > for Process < P1 > { type In < T > = (u32 , T) ; type Out < T > = T ; fn is_demux () -> bool { true } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < C1 , P2 > CanSend < Process < P2 > > for Cluster < C1 > { type In < T > = T ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { false } fn is_tagged () -> bool { true } } # [cfg (stageleft_macro)] impl < C1 , C2 > CanSend < Cluster < C2 > > for Cluster < C1 > { type In < T > = (u32 , T) ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { true } fn is_tagged () -> bool { true } } } pub use location :: { Cluster , Process } ; pub mod deploy { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use stageleft :: Quoted ; pub mod graphs { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use super :: { LocalDeploy , Node , ProcessSpec } ; pub use crate :: deploy :: graphs :: SingleProcessGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for SingleProcessGraph { type Process = SingleNode ; type Cluster = SingleNode ; type Meta = () ; type GraphId = () ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { SingleNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { SingleNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , SingleProcessGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> SingleNode { SingleNode { } } } pub use crate :: deploy :: graphs :: SingleNode ; # [cfg (stageleft_macro)] impl Node for SingleNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } pub use crate :: deploy :: graphs :: MultiGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for MultiGraph { type Process = MultiNode ; type Cluster = MultiNode ; type Meta = () ; type GraphId = usize ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { MultiNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { MultiNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , MultiGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> MultiNode { MultiNode { } } } pub use crate :: deploy :: graphs :: MultiNode ; # [cfg (stageleft_macro)] impl Node for MultiNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } } pub use graphs :: * ; pub use crate :: deploy :: LocalDeploy ; pub use crate :: deploy :: Deploy ; # [cfg (stageleft_macro)] impl < 'a , T : Deploy < 'a , Process = N , Cluster = C , Meta = M , GraphId = R > , N : Node < Meta = M > , C : Node < Meta = M > , M : Default , R , > LocalDeploy < 'a > for T { type Process = N ; type Cluster = C ; type Meta = M ; type GraphId = R ; fn has_trivial_node () -> bool { < T as Deploy < 'a > > :: has_trivial_node () } fn trivial_process (id : usize) -> Self :: Process { < T as Deploy < 'a > > :: trivial_process (id) } fn trivial_cluster (id : usize) -> Self :: Cluster { < T as Deploy < 'a > > :: trivail_cluster (id) } } pub use crate :: deploy :: ProcessSpec ; pub use crate :: deploy :: ClusterSpec ; pub use crate :: deploy :: Node ; } pub use deploy :: { ClusterSpec , Deploy , ProcessSpec } ; pub mod cycle { pub use std :: marker :: PhantomData ; pub use crate :: builder :: FlowLeaves ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: cycle :: CycleComplete ; pub use crate :: cycle :: CycleCollection ; pub use crate :: cycle :: CycleCollectionWithInitial ; pub use crate :: cycle :: HfCycle ; # [cfg (stageleft_macro)] impl < 'a , S : CycleComplete < 'a > > HfCycle < 'a , S > { pub fn complete (self , stream : S) { let ident = self . ident ; S :: complete (stream , ident) } } } pub use cycle :: HfCycle ; pub mod builder { pub use std :: cell :: RefCell ; pub use std :: collections :: HashMap ; pub use std :: marker :: PhantomData ; pub use std :: rc :: Rc ; pub use std :: time :: Duration ; pub use hydroflow :: futures :: stream :: Stream as FuturesStream ; pub use hydroflow :: { tokio , tokio_stream } ; pub use internal :: TokenStream ; pub use proc_macro2 :: Span ; pub use quote :: quote ; pub use runtime_support :: FreeVariable ; pub use stageleft :: * ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Cluster , Location , LocationId , Process } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: { HfCycle , Optional , RuntimeContext , Singleton , Stream } ; pub mod built { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use hydroflow_lang :: graph :: { eliminate_extra_unions_tees , HydroflowGraph } ; pub use super :: deploy :: { DeployFlow , DeployResult } ; pub use crate :: deploy :: { ClusterSpec , Deploy , LocalDeploy , ProcessSpec } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Cluster , Process } ; pub use crate :: HfCompiled ; pub use crate :: builder :: built :: BuiltFlow ; # [cfg (stageleft_macro)] impl < 'a > Drop for BuiltFlow < 'a > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped BuiltFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn ir (& self) -> & Vec < HfPlusLeaf < 'a > > { & self . ir } pub fn optimize_with (mut self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> BuiltFlow < 'a > { self . used = true ; BuiltFlow { ir : f (std :: mem :: take (& mut self . ir)) , processes : std :: mem :: take (& mut self . processes) , clusters : std :: mem :: take (& mut self . clusters) , used : false , _phantom : PhantomData , } } } pub fn build_inner (ir : & mut Vec < HfPlusLeaf >) -> BTreeMap < usize , HydroflowGraph > { let mut builders = BTreeMap :: new () ; let mut built_tees = HashMap :: new () ; let mut next_stmt_id = 0 ; for leaf in ir { leaf . emit (& mut builders , & mut built_tees , & mut next_stmt_id) ; } builders . into_iter () . map (| (k , v) | { let (mut flat_graph , _ , _) = v . build () ; eliminate_extra_unions_tees (& mut flat_graph) ; (k , flat_graph) }) . collect () } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn compile_no_network < D : LocalDeploy < 'a > > (mut self) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; HfCompiled { hydroflow_ir : build_inner (& mut self . ir) , extra_stmts : BTreeMap :: new () , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> BuiltFlow < 'a > { self . optimize_with (crate :: persist_pullup :: persist_pullup) } fn into_deploy < D : LocalDeploy < 'a > > (mut self) -> DeployFlow < 'a , D > { self . used = true ; let processes = if D :: has_trivial_node () { self . processes . iter () . map (| id | (* id , D :: trivial_process (* id))) . collect () } else { HashMap :: new () } ; let clusters = if D :: has_trivial_node () { self . clusters . iter () . map (| id | (* id , D :: trivial_cluster (* id))) . collect () } else { HashMap :: new () } ; DeployFlow { ir : std :: mem :: take (& mut self . ir) , nodes : processes , clusters , used : false , _phantom : PhantomData , } } pub fn with_process < P , D : LocalDeploy < 'a > > (self , process : & Process < P > , spec : impl ProcessSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_process (process , spec) } pub fn with_cluster < C , D : LocalDeploy < 'a > > (self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_cluster (cluster , spec) } pub fn compile < D : Deploy < 'a > + 'a > (self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . into_deploy :: < D > () . compile (env) } pub fn deploy < D : Deploy < 'a , CompileEnv = () > + 'a > (self , env : & mut D :: InstantiateEnv ,) -> DeployResult < 'a , D > { self . into_deploy :: < D > () . deploy (env) } } } pub mod deploy { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use proc_macro2 :: Span ; pub use stageleft :: Quoted ; pub use super :: built :: build_inner ; pub use crate :: deploy :: { LocalDeploy , Node } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: { Cluster , ClusterSpec , Deploy , HfCompiled , Process , ProcessSpec } ; pub use crate :: builder :: deploy :: DeployFlow ; # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > Drop for DeployFlow < 'a , D > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped DeployFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > DeployFlow < 'a , D > { pub fn with_process < P > (mut self , process : & Process < P > , spec : impl ProcessSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < P > () . to_string () ; self . nodes . insert (process . id , spec . build (process . id , & tag_name)) ; self } pub fn with_cluster < C > (mut self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < C > () . to_string () ; self . clusters . insert (cluster . id , spec . build (cluster . id , & tag_name)) ; self } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployFlow < 'a , D > { pub fn compile (mut self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; let mut seen_tees : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | leaf . compile_network :: < D > (env , & mut seen_tees , & self . nodes , & self . clusters)) . collect () ; let extra_stmts = self . extra_stmts (env) ; HfCompiled { hydroflow_ir : build_inner (& mut ir_leaves_networked) , extra_stmts , _phantom : PhantomData , } } fn extra_stmts (& self , env : & < D as Deploy < 'a > > :: CompileEnv) -> BTreeMap < usize , Vec < syn :: Stmt > > { let all_locations_count = self . nodes . len () + self . clusters . len () ; let mut extra_stmts : BTreeMap < usize , Vec < syn :: Stmt > > = BTreeMap :: new () ; for & c_id in self . clusters . keys () { let self_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , c_id) , Span :: call_site () ,) ; let self_id_expr = D :: cluster_self_id (env) . splice () ; extra_stmts . entry (c_id) . or_default () . push (syn :: parse_quote ! { let # self_id_ident = # self_id_expr ; }) ; for other_location in 0 .. all_locations_count { let other_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , c_id) , Span :: call_site () ,) ; let other_id_expr = D :: cluster_ids (env , c_id) . splice () ; extra_stmts . entry (other_location) . or_default () . push (syn :: parse_quote ! { let # other_id_ident = # other_id_expr ; }) ; } } extra_stmts } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a , CompileEnv = () > > DeployFlow < 'a , D > { # [must_use] pub fn deploy (mut self , env : & mut D :: InstantiateEnv) -> DeployResult < 'a , D > { self . used = true ; let mut seen_tees_instantiate : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | { leaf . compile_network :: < D > (& () , & mut seen_tees_instantiate , & self . nodes , & self . clusters ,) }) . collect () ; let mut compiled = build_inner (& mut ir_leaves_networked) ; let mut extra_stmts = self . extra_stmts (& ()) ; let mut meta = D :: Meta :: default () ; let (mut processes , mut clusters) = (std :: mem :: take (& mut self . nodes) . into_iter () . map (| (node_id , node) | { node . instantiate (env , & mut meta , compiled . remove (& node_id) . unwrap () , extra_stmts . remove (& node_id) . unwrap_or_default () ,) ; (node_id , node) }) . collect :: < HashMap < _ , _ > > () , std :: mem :: take (& mut self . clusters) . into_iter () . map (| (cluster_id , cluster) | { cluster . instantiate (env , & mut meta , compiled . remove (& cluster_id) . unwrap () , extra_stmts . remove (& cluster_id) . unwrap_or_default () ,) ; (cluster_id , cluster) }) . collect :: < HashMap < _ , _ > > () ,) ; for node in processes . values_mut () { node . update_meta (& meta) ; } for cluster in clusters . values_mut () { cluster . update_meta (& meta) ; } let mut seen_tees_connect = HashMap :: new () ; for leaf in ir_leaves_networked { leaf . connect_network (& mut seen_tees_connect) ; } DeployResult { processes , clusters , } } } pub use crate :: builder :: deploy :: DeployResult ; # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployResult < 'a , D > { pub fn get_process < P > (& self , p : & Process < P >) -> & D :: Process { let id = match p . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . processes . get (& id) . unwrap () } pub fn get_cluster < C > (& self , c : & Cluster < C >) -> & D :: Cluster { let id = match c . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . clusters . get (& id) . unwrap () } } } # [doc = " Tracks the leaves of the dataflow IR. This is referenced by"] # [doc = " `Stream` and `HfCycle` to build the IR. The inner option will"] # [doc = " be set to `None` when this builder is finalized."] pub type FlowLeaves < 'a > = Rc < RefCell < Option < Vec < HfPlusLeaf < 'a > > > > > ; pub use crate :: builder :: ClusterIds ; # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Vec < u32 > > for ClusterIds < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , & 'a Vec < u32 > > for ClusterIds < 'a > { } # [derive (Copy , Clone)] pub struct ClusterSelfId < 'a > { pub id : usize , pub _phantom : PhantomData < & 'a mut & 'a u32 > , } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < u32 > for ClusterSelfId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , u32 > for ClusterSelfId < 'a > { } pub use crate :: builder :: FlowBuilder ; # [cfg (stageleft_macro)] impl < 'a > Drop for FlowBuilder < 'a > { fn drop (& mut self) { if ! self . finalized { panic ! ("Dropped FlowBuilder without finalizing, you may have forgotten to call `with_default_optimize`, `optimize_with`, or `finalize`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > QuotedContext for FlowBuilder < 'a > { fn create () -> Self { FlowBuilder :: new () } } # [cfg (stageleft_macro)] impl < 'a > FlowBuilder < 'a > { # [allow (clippy :: new_without_default)] pub fn new () -> FlowBuilder < 'a > { FlowBuilder { ir_leaves : Rc :: new (RefCell :: new (Some (Vec :: new ()))) , nodes : RefCell :: new (vec ! []) , clusters : RefCell :: new (vec ! []) , cycle_ids : RefCell :: new (HashMap :: new ()) , next_node_id : RefCell :: new (0) , finalized : false , _phantom : PhantomData , } } pub fn finalize (mut self) -> built :: BuiltFlow < 'a > { self . finalized = true ; built :: BuiltFlow { ir : self . ir_leaves . borrow_mut () . take () . unwrap () , processes : self . nodes . replace (vec ! []) , clusters : self . clusters . replace (vec ! []) , used : false , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> built :: BuiltFlow < 'a > { self . finalize () . with_default_optimize () } pub fn optimize_with (self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> built :: BuiltFlow < 'a > { self . finalize () . optimize_with (f) } pub fn ir_leaves (& self) -> & FlowLeaves < 'a > { & self . ir_leaves } pub fn process < P > (& self) -> Process < P > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . nodes . borrow_mut () . push (id) ; Process { id , _phantom : PhantomData , } } pub fn cluster < C > (& self) -> Cluster < C > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . clusters . borrow_mut () . push (id) ; Cluster { id , _phantom : PhantomData , } } pub fn runtime_context (& self) -> RuntimeContext < 'a > { RuntimeContext { _phantom : PhantomData , } } pub fn cluster_members < C > (& self , cluster : & Cluster < C > ,) -> impl Quoted < 'a , & 'a Vec < u32 > > + Copy + 'a { ClusterIds { id : cluster . id , _phantom : PhantomData , } } pub fn cluster_self_id < C > (& self , cluster : & Cluster < C >) -> impl Quoted < 'a , u32 > + Copy + 'a { ClusterSelfId { id : cluster . id , _phantom : PhantomData , } } pub fn spin < L : Location > (& self , on : & L) -> Stream < 'a , () , Unbounded , NoTick , L > { Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Spin () , location_kind : on . id () , })) ,) } pub fn spin_batch < L : Location > (& self , on : & L , batch_size : impl Quoted < 'a , usize > + Copy + 'a ,) -> Stream < 'a , () , Bounded , Tick , L > { self . spin (on) . flat_map (q ! (move | _ | 0 .. batch_size)) . map (q ! (| _ | ())) . tick_batch () } pub fn source_stream < T , E : FuturesStream < Item = T > + Unpin , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Unbounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Stream (e . into ()) , location_kind : on . id () , })) ,) } pub fn source_iter < T , E : IntoIterator < Item = T > , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Bounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , })) ,) } pub fn singleton < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Singleton < 'a , T , Bounded , NoTick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Singleton :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,)))) ,) } pub fn singleton_first_tick < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Optional < 'a , T , Bounded , Tick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,) } pub fn source_interval < L : Location > (& self , on : & L , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , () , Unbounded , NoTick , L > { let interval = interval . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : on . id () , })) ,) } pub fn source_interval_delayed < L : Location > (& self , on : & L , delay : impl Quoted < 'a , Duration > + Copy + 'a , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , tokio :: time :: Instant , Unbounded , NoTick , L > { self . source_stream (on , q ! (tokio_stream :: wrappers :: IntervalStream :: new (tokio :: time :: interval_at (tokio :: time :: Instant :: now () + delay , interval))) ,) . tick_batch () . first () . latest () } pub fn cycle < S : CycleCollection < 'a > > (& self , on : & S :: Location) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , on . id ()) ,) } pub fn cycle_with_initial < S : CycleCollectionWithInitial < 'a > > (& self , on : & S :: Location , initial : S ,) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , initial , on . id ()) ,) } } } pub use builder :: FlowBuilder ; pub mod ir { pub use core :: panic ; pub use std :: cell :: RefCell ; pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow_lang :: graph :: FlatGraphBuilder ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: ToTokens ; pub use syn :: parse_quote ; pub use crate :: deploy :: Deploy ; pub use crate :: location :: LocationId ; pub use crate :: ir :: DebugExpr ; # [cfg (stageleft_macro)] impl From < syn :: Expr > for DebugExpr { fn from (expr : syn :: Expr) -> DebugExpr { DebugExpr (expr) } } # [cfg (stageleft_macro)] impl Deref for DebugExpr { type Target = syn :: Expr ; fn deref (& self) -> & Self :: Target { & self . 0 } } # [cfg (stageleft_macro)] impl ToTokens for DebugExpr { fn to_tokens (& self , tokens : & mut TokenStream) { self . 0 . to_tokens (tokens) ; } } # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugExpr { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "{}" , self . 0 . to_token_stream ()) } } pub use crate :: ir :: DebugInstantiate ; # [cfg (stageleft_macro)] impl < 'a > std :: fmt :: Debug for DebugInstantiate < 'a > { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<network instantiate>") } } pub use crate :: ir :: DebugPipelineFn ; # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugPipelineFn { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<function>") } } pub use crate :: ir :: HfPlusSource ; pub use crate :: ir :: HfPlusLeaf ; # [cfg (stageleft_macro)] impl < 'a > HfPlusLeaf < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . compile_network :: < D > (compile_env , s , nodes , clusters) ; } , seen_tees ,) } pub fn connect_network (self , seen_tees : & mut SeenTees < 'a >) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . connect_network (s) ; } , seen_tees ,) } pub fn transform_children (self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) -> HfPlusLeaf < 'a > { match self { HfPlusLeaf :: ForEach { f , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: ForEach { f , input } } HfPlusLeaf :: DestSink { sink , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: DestSink { sink , input } } HfPlusLeaf :: CycleSink { ident , location_kind , mut input , } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: CycleSink { ident , location_kind , input , } } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) { match self { HfPlusLeaf :: ForEach { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> for_each (# f) ; }) ; } HfPlusLeaf :: DestSink { sink , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink) ; }) ; } HfPlusLeaf :: CycleSink { ident , location_kind , input , } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; assert_eq ! (input_location_id , * location_id , "cycle_sink location mismatch") ; graph_builders . entry (* location_id) . or_default () . add_statement (parse_quote ! { # ident = # input_ident ; }) ; } } } } pub use crate :: ir :: HfPlusNode ; pub type SeenTees < 'a > = HashMap < * const RefCell < HfPlusNode < 'a > > , Rc < RefCell < HfPlusNode < 'a > > > > ; # [cfg (stageleft_macro)] impl < 'a > HfPlusNode < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (& mut self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) { self . transform_children (| n , s | n . compile_network :: < D > (compile_env , s , nodes , clusters) , seen_tees ,) ; if let HfPlusNode :: Network { from_location , to_location , instantiate_fn , .. } = self { let (sink_expr , source_expr , connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { let ((sink , source) , connect_fn) = match (from_location , to_location) { (LocationId :: Process (from) , LocationId :: Process (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: o2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Process (from) , LocationId :: Cluster (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: o2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Process (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: m2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Cluster (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: m2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } } ; (sink , source , connect_fn) } DebugInstantiate :: Finalized (_ , _ , _) => panic ! ("network already finalized") , } ; * instantiate_fn = DebugInstantiate :: Finalized (sink_expr , source_expr , connect_fn) ; } } pub fn connect_network (& mut self , seen_tees : & mut SeenTees < 'a >) { self . transform_children (| n , s | n . connect_network (s) , seen_tees) ; if let HfPlusNode :: Network { instantiate_fn , .. } = self { match instantiate_fn { DebugInstantiate :: Building () => panic ! ("network not built") , DebugInstantiate :: Finalized (_ , _ , ref connect_fn) => { connect_fn () ; } } } } pub fn transform_children (& mut self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) { match self { HfPlusNode :: Placeholder => { panic ! () ; } HfPlusNode :: Source { .. } => { } HfPlusNode :: CycleSource { .. } => { } HfPlusNode :: Tee { inner } => { if let Some (transformed) = seen_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { * inner = transformed . clone () ; } else { let transformed_cell = Rc :: new (RefCell :: new (HfPlusNode :: Placeholder)) ; seen_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , transformed_cell . clone () ,) ; let mut orig = inner . replace (HfPlusNode :: Placeholder) ; transform (& mut orig , seen_tees) ; * transformed_cell . borrow_mut () = orig ; * inner = transformed_cell ; } } HfPlusNode :: Persist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Unpersist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Delta (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Union (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossProduct (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossSingleton (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Join (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Difference (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: AntiJoin (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Map { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FlatMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Filter { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FilterMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Sort (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: DeferTick (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Enumerate (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Inspect { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Unique (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Fold { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FoldKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Reduce { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: ReduceKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Network { input , .. } => { transform (input . as_mut () , seen_tees) ; } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) -> (syn :: Ident , usize) { match self { HfPlusNode :: Placeholder => { panic ! () } HfPlusNode :: Persist (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let persist_id = * next_stmt_id ; * next_stmt_id += 1 ; let persist_ident = syn :: Ident :: new (& format ! ("stream_{}" , persist_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # persist_ident = # inner_ident -> persist ::<'static > () ; }) ; (persist_ident , location) } HfPlusNode :: Unpersist (_) => { panic ! ("Unpersist is a marker node and should have been optimized away. This is likely a compiler bug.") } HfPlusNode :: Delta (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let delta_id = * next_stmt_id ; * next_stmt_id += 1 ; let delta_ident = syn :: Ident :: new (& format ! ("stream_{}" , delta_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # delta_ident = # inner_ident -> multiset_delta () ; }) ; (delta_ident , location) } HfPlusNode :: Source { source , location_kind , } => { let source_id = * next_stmt_id ; * next_stmt_id += 1 ; let source_ident = syn :: Ident :: new (& format ! ("stream_{}" , source_id) , Span :: call_site ()) ; let source_stmt = match source { HfPlusSource :: Stream (expr) => { parse_quote ! { # source_ident = source_stream (# expr) ; } } HfPlusSource :: Iter (expr) => { parse_quote ! { # source_ident = source_iter (# expr) ; } } HfPlusSource :: Interval (expr) => { parse_quote ! { # source_ident = source_interval (# expr) ; } } HfPlusSource :: Spin () => { parse_quote ! { # source_ident = spin () ; } } } ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; graph_builders . entry (* location_id) . or_default () . add_statement (source_stmt) ; (source_ident , * location_id) } HfPlusNode :: CycleSource { ident , location_kind , } => { let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; (ident . clone () , * location_id) } HfPlusNode :: Tee { inner } => { if let Some (ret) = built_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { ret . clone () } else { let (inner_ident , inner_location_id) = inner . borrow () . emit (graph_builders , built_tees , next_stmt_id) ; let tee_id = * next_stmt_id ; * next_stmt_id += 1 ; let tee_ident = syn :: Ident :: new (& format ! ("stream_{}" , tee_id) , Span :: call_site ()) ; let builder = graph_builders . entry (inner_location_id) . or_default () ; builder . add_statement (parse_quote ! { # tee_ident = # inner_ident -> tee () ; }) ; built_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , (tee_ident . clone () , inner_location_id) ,) ; (tee_ident , inner_location_id) } } HfPlusNode :: Union (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "union inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let union_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # union_ident = union () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [0] # union_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # union_ident ; }) ; (union_ident , left_location_id) } HfPlusNode :: CrossSingleton (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "cross_singleton inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let cross_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # cross_ident = cross_singleton () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [input] # cross_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [single] # cross_ident ; }) ; (cross_ident , left_location_id) } HfPlusNode :: CrossProduct (..) | HfPlusNode :: Join (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: CrossProduct (..)) { parse_quote ! (cross_join_multiset) } else { parse_quote ! (join_multiset) } ; let (HfPlusNode :: CrossProduct (left , right) | HfPlusNode :: Join (left , right)) = self else { unreachable ! () } ; let (left_inner , left_was_persist) = if let HfPlusNode :: Persist (left) = left . as_ref () { (left , true) } else { (left , false) } ; let (right_inner , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left_inner . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right_inner . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "join / cross product inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; match (left_was_persist , right_was_persist) { (true , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'static > () ; }) ; } (true , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'tick > () ; }) ; } (false , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } (false , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } } ; builder . add_statement (parse_quote ! { # left_ident -> [0] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Difference (..) | HfPlusNode :: AntiJoin (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Difference (..)) { parse_quote ! (difference_multiset) } else { parse_quote ! (anti_join_multiset) } ; let (HfPlusNode :: Difference (left , right) | HfPlusNode :: AntiJoin (left , right)) = self else { unreachable ! () } ; let (right , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "difference / anti join inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; if right_was_persist { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } else { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } builder . add_statement (parse_quote ! { # left_ident -> [pos] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [neg] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Map { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let map_id = * next_stmt_id ; * next_stmt_id += 1 ; let map_ident = syn :: Ident :: new (& format ! ("stream_{}" , map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # map_ident = # input_ident -> map (# f) ; }) ; (map_ident , input_location_id) } HfPlusNode :: FlatMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let flat_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let flat_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , flat_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # flat_map_ident = # input_ident -> flat_map (# f) ; }) ; (flat_map_ident , input_location_id) } HfPlusNode :: Filter { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_ident = # input_ident -> filter (# f) ; }) ; (filter_ident , input_location_id) } HfPlusNode :: FilterMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_map_ident = # input_ident -> filter_map (# f) ; }) ; (filter_map_ident , input_location_id) } HfPlusNode :: Sort (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sort_id = * next_stmt_id ; * next_stmt_id += 1 ; let sort_ident = syn :: Ident :: new (& format ! ("stream_{}" , sort_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # sort_ident = # input_ident -> sort () ; }) ; (sort_ident , input_location_id) } HfPlusNode :: DeferTick (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let defer_tick_id = * next_stmt_id ; * next_stmt_id += 1 ; let defer_tick_ident = syn :: Ident :: new (& format ! ("stream_{}" , defer_tick_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # defer_tick_ident = # input_ident -> defer_tick_lazy () ; }) ; (defer_tick_ident , input_location_id) } HfPlusNode :: Enumerate (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let enumerate_id = * next_stmt_id ; * next_stmt_id += 1 ; let enumerate_ident = syn :: Ident :: new (& format ! ("stream_{}" , enumerate_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # enumerate_ident = # input_ident -> enumerate () ; }) ; (enumerate_ident , input_location_id) } HfPlusNode :: Inspect { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let inspect_id = * next_stmt_id ; * next_stmt_id += 1 ; let inspect_ident = syn :: Ident :: new (& format ! ("stream_{}" , inspect_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # inspect_ident = # input_ident -> inspect (# f) ; }) ; (inspect_ident , input_location_id) } HfPlusNode :: Unique (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let unique_id = * next_stmt_id ; * next_stmt_id += 1 ; let unique_ident = syn :: Ident :: new (& format ! ("stream_{}" , unique_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # unique_ident = # input_ident -> unique ::<'tick > () ; }) ; (unique_ident , input_location_id) } HfPlusNode :: Fold { .. } | HfPlusNode :: FoldKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Fold { .. }) { parse_quote ! (fold) } else { parse_quote ! (fold_keyed) } ; let (HfPlusNode :: Fold { init , acc , input } | HfPlusNode :: FoldKeyed { init , acc , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let fold_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'static > (# init , # acc) ; }) ; } else { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'tick > (# init , # acc) ; }) ; } (fold_ident , input_location_id) } HfPlusNode :: Reduce { .. } | HfPlusNode :: ReduceKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Reduce { .. }) { parse_quote ! (reduce) } else { parse_quote ! (reduce_keyed) } ; let (HfPlusNode :: Reduce { f , input } | HfPlusNode :: ReduceKeyed { f , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let reduce_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'static > (# f) ; }) ; } else { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'tick > (# f) ; }) ; } (reduce_ident , input_location_id) } HfPlusNode :: Network { from_location : _ , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input , } => { let (sink_expr , source_expr , _connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { panic ! ("Expected the network to be finalized") } DebugInstantiate :: Finalized (sink , source , connect_fn) => { (sink , source , connect_fn) } } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sender_builder = graph_builders . entry (input_location_id) . or_default () ; if let Some (serialize_pipeline) = serialize_pipeline { sender_builder . add_statement (parse_quote ! { # input_ident -> # serialize_pipeline -> dest_sink (# sink_expr) ; }) ; } else { sender_builder . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink_expr) ; }) ; } let to_id = match to_location { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let receiver_builder = graph_builders . entry (* to_id) . or_default () ; let receiver_stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let receiver_stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , receiver_stream_id) , Span :: call_site ()) ; if let Some (deserialize_pipeline) = deserialize_pipeline { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) -> # deserialize_pipeline ; }) ; } else { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) ; }) ; } (receiver_stream_ident , * to_id) } } } } } pub mod persist_pullup { pub use std :: cell :: RefCell ; pub use std :: collections :: HashSet ; pub use std :: ops :: Deref ; pub use crate :: ir :: * ; pub fn persist_pullup_node < 'a > (node : & mut HfPlusNode < 'a > , seen_tees : & mut SeenTees < 'a > , persist_pulled_tees : & mut HashSet < * const RefCell < HfPlusNode < 'a > > > ,) { node . transform_children (| n , s | persist_pullup_node (n , s , persist_pulled_tees) , seen_tees ,) ; match node { HfPlusNode :: Unpersist (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Unpersist (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Delta (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Delta (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Tee { inner } => { if persist_pulled_tees . contains (& (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >)) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } else { let inner_borrow = inner . borrow () ; if let HfPlusNode :: Persist (_) = inner_borrow . deref () { drop (inner_borrow) ; persist_pulled_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >) ; if let HfPlusNode :: Persist (box behind_persist) = inner . replace (HfPlusNode :: Placeholder) { * inner . borrow_mut () = behind_persist ; } else { unreachable ! () } * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } } } HfPlusNode :: Map { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Map { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Map { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: FlatMap { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: FlatMap { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: FlatMap { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Filter { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Filter { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Filter { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Network { input : box HfPlusNode :: Persist (_) , .. } => { if let HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Union (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Union (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Union (left , right))) ; } else { unreachable ! () } } HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: CrossProduct (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,) ,)))) ; } else { unreachable ! () } } HfPlusNode :: Join (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Join (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: Join (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,))))) ; } else { unreachable ! () } } _ => { } } } pub fn persist_pullup (ir : Vec < HfPlusLeaf >) -> Vec < HfPlusLeaf > { let mut seen_tees = Default :: default () ; let mut persist_pulled_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| n , s | persist_pullup_node (n , s , & mut persist_pulled_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn persist_pullup_through_map () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } # [test] fn persist_pullup_behind_tee () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; let before_tee = flow . source_iter (& process , q ! (0 .. 10)) . tick_batch () . persist () ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } } } pub mod profiler { pub use std :: cell :: RefCell ; pub use hydroflow :: futures :: channel :: mpsc :: UnboundedSender ; pub use stageleft :: * ; pub use crate as hydroflow_plus ; pub use crate :: ir :: * ; pub use crate :: RuntimeContext ; pub fn increment_counter (count : & mut u64) { * count += 1 ; } pub fn quoted_any_fn < 'a , F : Fn (& usize) + 'a , Q : IntoQuotedMut < 'a , F > > (q : Q) -> Q { q } # [doc = " Add a profiling node before each node to count the cardinality of its input"] pub fn add_profiling_node < 'a > (node : & mut HfPlusNode < 'a > , _context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > , id : & mut u32 , seen_tees : & mut SeenTees < 'a > ,) { let my_id = * id ; * id += 1 ; node . transform_children (| node , seen_tees | { add_profiling_node (node , _context , counters , counter_queue , id , seen_tees) } , seen_tees ,) ; let orig_node = std :: mem :: replace (node , HfPlusNode :: Placeholder) ; * node = HfPlusNode :: Inspect { f : quoted_any_fn (q ! ({ counter_queue . borrow () . unbounded_send ((my_id as usize , counters . borrow () [my_id as usize])) . unwrap () ; counters . borrow_mut () [my_id as usize] = 0 ; move | _ | { hydroflow_plus :: profiler :: increment_counter (& mut counters . borrow_mut () [my_id as usize] ,) ; } })) . splice () . into () , input : Box :: new (orig_node) , } } # [doc = " Count the cardinality of each input and periodically output to a file"] pub fn profiling < 'a > (ir : Vec < HfPlusLeaf < 'a > > , context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > ,) -> Vec < HfPlusLeaf < 'a > > { let mut id = 0 ; let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | { add_profiling_node (node , context , counters , counter_queue , & mut id , seen_tees) } , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn profiler_wrapping_all_operators () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let runtime_context = flow . runtime_context () ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (& built . ir ()) ; let counters = RuntimeData :: new ("Fake") ; let counter_queue = RuntimeData :: new ("Fake") ; let pushed_down = built . with_default_optimize () . optimize_with (| ir | super :: profiling (ir , runtime_context , counters , counter_queue)) ; insta :: assert_debug_snapshot ! (& pushed_down . ir ()) ; let _ = pushed_down . compile_no_network :: < MultiGraph > () ; } } } pub mod properties { pub use std :: collections :: HashSet ; pub use stageleft :: * ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , SeenTees } ; pub use crate :: properties :: PropertyDatabase ; # [doc = " Allows us to convert the hydroflow datatype for folds to a binary operation for the algebra"] # [doc = " property tests."] # [allow (dead_code)] pub fn convert_hf_to_binary < I , A : Default , F : Fn (& mut A , I) > (f : F) -> impl Fn (I , I) -> A { move | a , b | { let mut acc = Default :: default () ; f (& mut acc , a) ; f (& mut acc , b) ; acc } } # [cfg (stageleft_macro)] impl PropertyDatabase { # [doc = " Tags the expression as commutative."] pub fn add_commutative_tag < 'a , I , A , F : Fn (& mut A , I) , Q : Quoted < 'a , F > + Clone > (& mut self , expr : Q ,) -> Q { let expr_clone = expr . clone () ; self . commutative . insert (expr_clone . splice ()) ; expr } pub fn is_tagged_commutative (& self , expr : & syn :: Expr) -> bool { self . commutative . contains (expr) } } pub fn properties_optimize_node < 'a > (node : & mut HfPlusNode < 'a > , db : & PropertyDatabase , seen_tees : & mut SeenTees < 'a > ,) { node . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , seen_tees ,) ; match node { HfPlusNode :: ReduceKeyed { f , .. } if db . is_tagged_commutative (& f . 0) => { dbg ! ("IDENTIFIED COMMUTATIVE OPTIMIZATION for {:?}" , & f) ; } _ => { } } } pub fn properties_optimize < 'a > (ir : Vec < HfPlusLeaf < 'a > > , db : & PropertyDatabase ,) -> Vec < HfPlusLeaf < 'a > > { let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use super :: * ; use crate :: deploy :: SingleProcessGraph ; use crate :: FlowBuilder ; # [test] fn test_property_database () { let mut db = PropertyDatabase :: default () ; assert ! (! db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; let _ = db . add_commutative_tag (q ! (| a : & mut i32 , b : i32 | * a += b)) ; assert ! (db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; } # [test] fn test_property_optimized () { let flow = FlowBuilder :: new () ; let mut database = PropertyDatabase :: default () ; let process = flow . process :: < () > () ; let counter_func = q ! (| count : & mut i32 , _ | * count += 1) ; let _ = database . add_commutative_tag (counter_func) ; flow . source_iter (& process , q ! (vec ! [])) . map (q ! (| string : String | (string , ()))) . tick_batch () . fold_keyed (q ! (|| 0) , counter_func) . all_ticks () . for_each (q ! (| (string , count) | println ! ("{}: {}" , string , count))) ; let built = flow . finalize () . optimize_with (| ir | properties_optimize (ir , & database)) . with_default_optimize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let _ = built . compile_no_network :: < SingleProcessGraph > () ; } } } pub use crate :: RuntimeContext ; # [cfg (stageleft_macro)] impl Copy for RuntimeContext < '_ > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Context > for RuntimeContext < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (quote ! (& context))) } } pub use crate :: HfCompiled ; # [cfg (stageleft_macro)] impl < 'a , ID > HfCompiled < 'a , ID > { pub fn hydroflow_ir (& self) -> & BTreeMap < usize , HydroflowGraph > { & self . hydroflow_ir } } # [cfg (stageleft_macro)] impl < 'a > HfCompiled < 'a , usize > { pub fn with_dynamic_id (self , id : impl Quoted < 'a , usize >) -> HfBuiltWithId < 'a > { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; let mut conditioned_tokens = None ; for (subgraph_id , flat_graph) in self . hydroflow_ir { let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; let my_extra_stmts = self . extra_stmts . get (& subgraph_id) . cloned () . unwrap_or_default () ; if let Some (conditioned_tokens) = conditioned_tokens . as_mut () { * conditioned_tokens = syn :: parse_quote ! { # conditioned_tokens else if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } } ; } else { conditioned_tokens = Some (syn :: parse_quote ! { if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } }) ; } } let conditioned_tokens : TokenStream = conditioned_tokens . unwrap () ; let id = id . splice () ; HfBuiltWithId { tokens : syn :: parse_quote ! ({ let __given_id = # id ; # conditioned_tokens else { panic ! ("Invalid node id: {}" , __given_id) ; } }) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfCompiled < 'a , () > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfCompiled < 'a , () > { fn to_tokens (mut self) -> (Option < TokenStream > , Option < TokenStream >) { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; if self . hydroflow_ir . len () != 1 { panic ! ("Expected exactly one subgraph in the Hydroflow IR") ; } let flat_graph = self . hydroflow_ir . remove (& 0) . unwrap () ; let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; (None , Some (tokens)) } } pub use crate :: HfBuiltWithId ; # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfBuiltWithId < 'a > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfBuiltWithId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (self . tokens)) } }
[INFO] [stdout] 1 + pub use std :: collections :: BTreeMap ; pub use std :: marker :: PhantomData ; pub use hydroflow :: scheduled :: context :: Context ; pub use hydroflow :: scheduled :: graph :: Hydroflow ; pub use hydroflow :: * ; pub use lang :: graph :: { partition_graph , HydroflowGraph } ; pub use proc_macro2 :: TokenStream ; pub use quote :: quote ; pub use stageleft :: runtime_support :: FreeVariable ; pub use stageleft :: Quoted ; pub mod runtime_support { pub use bincode ; } pub mod stream { pub use std :: cell :: RefCell ; pub use std :: hash :: Hash ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow :: bytes :: Bytes ; pub use hydroflow :: futures :: Sink ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: quote ; pub use serde :: de :: DeserializeOwned ; pub use serde :: Serialize ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use syn :: parse_quote ; pub use crate :: builder :: { ClusterIds , FlowLeaves } ; pub use crate :: cycle :: { CycleCollection , CycleComplete } ; pub use crate :: ir :: { DebugInstantiate , HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { CanSend , Location , LocationId } ; pub use crate :: { Cluster , Optional , Singleton } ; pub use crate :: stream :: Unbounded ; pub use crate :: stream :: Bounded ; pub use crate :: stream :: NoTick ; pub use crate :: stream :: Tick ; pub use crate :: stream :: Stream ; # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Stream { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Stream < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Stream { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , C , N > > ,) -> Stream < 'a , (T , O) , W , C , N > where O : Clone , { let other : Optional < 'a , O , Bounded , C , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn cross_product < O > (self , other : Stream < 'a , O , W , C , N >) -> Stream < 'a , (T , O) , W , C , N > where T : Clone , O : Clone , { if self . location_kind != other . location_kind { panic ! ("cross_product must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossProduct (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn union (self , other : Stream < 'a , T , W , C , N >) -> Stream < 'a , T , W , C , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn dest_sink < S : Unpin + Sink < T > + 'a > (self , sink : impl Quoted < 'a , S >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: DestSink { sink : sink . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn first (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } # [doc = " Allow this stream through if the other stream has elements, otherwise the output is empty."] pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } # [doc = " Allow this stream through if the other stream is empty, otherwise the output is empty."] pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn enumerate (self) -> Stream < 'a , (usize , T) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Enumerate (Box :: new (self . ir_node . into_inner ())) ,) } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn sort (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Ord , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Sort (Box :: new (self . ir_node . into_inner ())) ,) } pub fn count (self) -> Singleton < 'a , usize , Bounded , Tick , N > { self . fold (q ! (|| 0usize) , q ! (| count , _ | * count += 1)) } pub fn delta (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } pub fn unique (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Eq + Hash , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unique (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn tick_batch (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_prefix (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { self . tick_batch () . persist () } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn for_each < F : Fn (T) + 'a > (self , f : impl IntoQuotedMut < 'a , F >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: ForEach { input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , f : f . splice () . into () , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Unbounded , NoTick , N > { pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . tick_batch () . continue_if (samples . first ()) . all_ticks () } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Unbounded , NoTick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , C , N : Location > Stream < 'a , T , Bounded , C , N > { pub fn filter_not_in (self , other : Stream < 'a , T , Bounded , C , N >) -> Stream < 'a , T , Bounded , C , N > where T : Eq + Hash , { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Difference (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Stream < 'a , & T , W , C , N > { pub fn cloned (self) -> Stream < 'a , T , W , C , N > { self . map (q ! (| d | d . clone ())) } } # [cfg (stageleft_macro)] impl < 'a , K , V1 , W , C , N : Location > Stream < 'a , (K , V1) , W , C , N > { pub fn join < W2 , V2 > (self , n : Stream < 'a , (K , V2) , W2 , C , N > ,) -> Stream < 'a , (K , (V1 , V2)) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Join (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } pub fn anti_join < W2 > (self , n : Stream < 'a , K , W2 , C , N >) -> Stream < 'a , (K , V1) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("anti_join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: AntiJoin (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , K : Eq + Hash , V , N : Location > Stream < 'a , (K , V) , Bounded , Tick , N > { pub fn fold_keyed < A , I : Fn () -> A + 'a , F : Fn (& mut A , V) + 'a > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , A) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FoldKeyed { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce_keyed < F : Fn (& mut V , V) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , V) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: ReduceKeyed { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } pub fn get_this_crate () -> TokenStream { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , Span :: call_site ()) ; quote ! { # ident } } } } pub fn serialize_bincode < T : Serialize > (is_demux : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if is_demux { parse_quote ! { map (| (id , data) | { (id , # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into ()) }) } } else { parse_quote ! { map (| data | { # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into () }) } } } pub fn deserialize_bincode < T : DeserializeOwned > (tagged : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if tagged { parse_quote ! { map (| res | { let (id , b) = res . unwrap () ; (id , # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& b) . unwrap ()) }) } } else { parse_quote ! { map (| res | { # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& res . unwrap ()) . unwrap () }) } } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn send_bincode < N2 : Location , CoreType > (self , other : & N2 ,) -> Stream < 'a , N :: Out < CoreType > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T > , CoreType : Serialize + DeserializeOwned , { let serialize_pipeline = Some (serialize_bincode :: < CoreType > (N :: is_demux ())) ; let deserialize_pipeline = Some (deserialize_bincode :: < CoreType > (N :: is_tagged ())) ; Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bytes < N2 : Location > (self , other : & N2 ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T > , { Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline : None , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline : if N :: is_tagged () { Some (parse_quote ! (map (| (id , b) | (id , b . unwrap () . freeze ())))) } else { Some (parse_quote ! (map (| b | b . unwrap () . freeze ()))) } , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bincode_interleaved < N2 : Location , Tag , CoreType > (self , other : & N2 ,) -> Stream < 'a , CoreType , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T , Out < CoreType > = (Tag , CoreType) > , CoreType : Serialize + DeserializeOwned , { self . send_bincode :: < N2 , CoreType > (other) . map (q ! (| (_ , b) | b)) } pub fn send_bytes_interleaved < N2 : Location , Tag > (self , other : & N2 ,) -> Stream < 'a , Bytes , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T , Out < Bytes > = (Tag , Bytes) > , { self . send_bytes :: < N2 > (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bincode < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < T > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) > , T : Clone + Serialize + DeserializeOwned , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bincode (other) } pub fn broadcast_bincode_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , T , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) , Out < T > = (Tag , T) > + 'a , T : Clone + Serialize + DeserializeOwned , { self . broadcast_bincode (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bytes < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) > + 'a , T : Clone , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bytes (other) } pub fn broadcast_bytes_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , Bytes , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) , Out < Bytes > = (Tag , Bytes) > + 'a , T : Clone , { self . broadcast_bytes (other) . map (q ! (| (_ , b) | b)) } } } pub use stream :: { Bounded , NoTick , Stream , Tick , Unbounded } ; pub mod singleton { pub use std :: cell :: RefCell ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use crate :: builder :: FlowLeaves ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial , CycleComplete } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: Stream ; pub use crate :: singleton :: CrossResult ; # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Singleton < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Singleton :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } pub use crate :: singleton :: Singleton ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Singleton { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleComplete < 'a > for Singleton < 'a , T , Bounded , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleCollectionWithInitial < 'a > for Singleton < 'a , T , Bounded , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , initial : Self , l : LocationId ,) -> Self { Singleton :: new (l , ir_leaves , HfPlusNode :: Union (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , }) , initial . ir_node . into_inner () . into () ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Singleton < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Singleton { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , U , W , C , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (Self :: other_ir_node (other)) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Singleton < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CrossSingleton (Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , Box :: new (HfPlusNode :: Unpersist (Box :: new (Self :: other_ir_node (other)))) ,))) ,) } } pub use crate :: singleton :: Optional ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Optional { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } pub fn some (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: new (singleton . location_kind , singleton . ir_leaves , singleton . ir_node . into_inner () ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > From < Singleton < 'a , T , W , C , N > > for Optional < 'a , T , W , C , N > { fn from (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: some (singleton) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Optional < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Optional { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn into_stream (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , Tick , N > > ,) -> Optional < 'a , (T , O) , Bounded , Tick , N > where O : Clone , { let other : Optional < 'a , O , Bounded , Tick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn union (self , other : Optional < 'a , T , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Optional < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_samples (self) -> Stream < 'a , T , Unbounded , NoTick , N > { self . latest_tick () . all_ticks () } pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . latest_tick () . continue_if (samples . first ()) . latest () . tick_samples () } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Unbounded , NoTick , N > > ,) -> Optional < 'a , (T , O) , Unbounded , NoTick , N > where O : Clone , { let other : Optional < 'a , O , Unbounded , NoTick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } self . latest_tick () . cross_singleton (other . latest_tick ()) . latest () } } } pub use singleton :: { Optional , Singleton } ; pub mod location { pub use std :: marker :: PhantomData ; pub use crate :: location :: LocationId ; pub use crate :: location :: Location ; pub use crate :: location :: Process ; # [cfg (stageleft_macro)] impl < P > Clone for Process < P > { fn clone (& self) -> Self { Process { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < P > Location for Process < P > { fn id (& self) -> LocationId { LocationId :: Process (self . id) } } pub use crate :: location :: Cluster ; # [cfg (stageleft_macro)] impl < C > Clone for Cluster < C > { fn clone (& self) -> Self { Cluster { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < C > Location for Cluster < C > { fn id (& self) -> LocationId { LocationId :: Cluster (self . id) } } pub use crate :: location :: CanSend ; # [cfg (stageleft_macro)] impl < P1 , P2 > CanSend < Process < P2 > > for Process < P1 > { type In < T > = T ; type Out < T > = T ; fn is_demux () -> bool { false } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < P1 , C2 > CanSend < Cluster < C2 > > for Process < P1 > { type In < T > = (u32 , T) ; type Out < T > = T ; fn is_demux () -> bool { true } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < C1 , P2 > CanSend < Process < P2 > > for Cluster < C1 > { type In < T > = T ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { false } fn is_tagged () -> bool { true } } # [cfg (stageleft_macro)] impl < C1 , C2 > CanSend < Cluster < C2 > > for Cluster < C1 > { type In < T > = (u32 , T) ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { true } fn is_tagged () -> bool { true } } } pub use location :: { Cluster , Process } ; pub mod deploy { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use stageleft :: Quoted ; pub mod graphs { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use super :: { LocalDeploy , Node , ProcessSpec } ; pub use crate :: deploy :: graphs :: SingleProcessGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for SingleProcessGraph { type Process = SingleNode ; type Cluster = SingleNode ; type Meta = () ; type GraphId = () ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { SingleNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { SingleNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , SingleProcessGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> SingleNode { SingleNode { } } } pub use crate :: deploy :: graphs :: SingleNode ; # [cfg (stageleft_macro)] impl Node for SingleNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } pub use crate :: deploy :: graphs :: MultiGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for MultiGraph { type Process = MultiNode ; type Cluster = MultiNode ; type Meta = () ; type GraphId = usize ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { MultiNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { MultiNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , MultiGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> MultiNode { MultiNode { } } } pub use crate :: deploy :: graphs :: MultiNode ; # [cfg (stageleft_macro)] impl Node for MultiNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } } pub use graphs :: * ; pub use crate :: deploy :: LocalDeploy ; pub use crate :: deploy :: Deploy ; # [cfg (stageleft_macro)] impl < 'a , T : Deploy < 'a , Process = N , Cluster = C , Meta = M , GraphId = R > , N : Node < Meta = M > , C : Node < Meta = M > , M : Default , R , > LocalDeploy < 'a > for T { type Process = N ; type Cluster = C ; type Meta = M ; type GraphId = R ; fn has_trivial_node () -> bool { < T as Deploy < 'a > > :: has_trivial_node () } fn trivial_process (id : usize) -> Self :: Process { < T as Deploy < 'a > > :: trivial_process (id) } fn trivial_cluster (id : usize) -> Self :: Cluster { < T as Deploy < 'a > > :: trivail_cluster (id) } } pub use crate :: deploy :: ProcessSpec ; pub use crate :: deploy :: ClusterSpec ; pub use crate :: deploy :: Node ; } pub use deploy :: { ClusterSpec , Deploy , ProcessSpec } ; pub mod cycle { pub use std :: marker :: PhantomData ; pub use crate :: builder :: FlowLeaves ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: cycle :: CycleComplete ; pub use crate :: cycle :: CycleCollection ; pub use crate :: cycle :: CycleCollectionWithInitial ; pub use crate :: cycle :: HfCycle ; # [cfg (stageleft_macro)] impl < 'a , S : CycleComplete < 'a > > HfCycle < 'a , S > { pub fn complete (self , stream : S) { let ident = self . ident ; S :: complete (stream , ident) } } } pub use cycle :: HfCycle ; pub mod builder { pub use std :: cell :: RefCell ; pub use std :: collections :: HashMap ; pub use std :: marker :: PhantomData ; pub use std :: rc :: Rc ; pub use std :: time :: Duration ; pub use hydroflow :: futures :: stream :: Stream as FuturesStream ; pub use hydroflow :: { tokio , tokio_stream } ; pub use internal :: TokenStream ; pub use proc_macro2 :: Span ; pub use quote :: quote ; pub use runtime_support :: FreeVariable ; pub use stageleft :: * ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Cluster , Location , LocationId , Process } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: { HfCycle , Optional , RuntimeContext , Singleton , Stream } ; pub mod built { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use hydroflow_lang :: graph :: { eliminate_extra_unions_tees , HydroflowGraph } ; pub use super :: deploy :: { DeployFlow , DeployResult } ; pub use crate :: deploy :: { ClusterSpec , Deploy , LocalDeploy , ProcessSpec } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Cluster , Process } ; pub use crate :: HfCompiled ; pub use crate :: builder :: built :: BuiltFlow ; # [cfg (stageleft_macro)] impl < 'a > Drop for BuiltFlow < 'a > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped BuiltFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn ir (& self) -> & Vec < HfPlusLeaf < 'a > > { & self . ir } pub fn optimize_with (mut self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> BuiltFlow < 'a > { self . used = true ; BuiltFlow { ir : f (std :: mem :: take (& mut self . ir)) , processes : std :: mem :: take (& mut self . processes) , clusters : std :: mem :: take (& mut self . clusters) , used : false , _phantom : PhantomData , } } } pub fn build_inner (ir : & mut Vec < HfPlusLeaf >) -> BTreeMap < usize , HydroflowGraph > { let mut builders = BTreeMap :: new () ; let mut built_tees = HashMap :: new () ; let mut next_stmt_id = 0 ; for leaf in ir { leaf . emit (& mut builders , & mut built_tees , & mut next_stmt_id) ; } builders . into_iter () . map (| (k , v) | { let (mut flat_graph , _ , _) = v . build () ; eliminate_extra_unions_tees (& mut flat_graph) ; (k , flat_graph) }) . collect () } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn compile_no_network < D : LocalDeploy < 'a > > (mut self) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; HfCompiled { hydroflow_ir : build_inner (& mut self . ir) , extra_stmts : BTreeMap :: new () , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> BuiltFlow < 'a > { self . optimize_with (crate :: persist_pullup :: persist_pullup) } fn into_deploy < D : LocalDeploy < 'a > > (mut self) -> DeployFlow < 'a , D > { self . used = true ; let processes = if D :: has_trivial_node () { self . processes . iter () . map (| id | (* id , D :: trivial_process (* id))) . collect () } else { HashMap :: new () } ; let clusters = if D :: has_trivial_node () { self . clusters . iter () . map (| id | (* id , D :: trivial_cluster (* id))) . collect () } else { HashMap :: new () } ; DeployFlow { ir : std :: mem :: take (& mut self . ir) , nodes : processes , clusters , used : false , _phantom : PhantomData , } } pub fn with_process < P , D : LocalDeploy < 'a > > (self , process : & Process < P > , spec : impl ProcessSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_process (process , spec) } pub fn with_cluster < C , D : LocalDeploy < 'a > > (self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_cluster (cluster , spec) } pub fn compile < D : Deploy < 'a > + 'a > (self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . into_deploy :: < D > () . compile (env) } pub fn deploy < D : Deploy < 'a , CompileEnv = () > + 'a > (self , env : & mut D :: InstantiateEnv ,) -> DeployResult < 'a , D > { self . into_deploy :: < D > () . deploy (env) } } } pub mod deploy { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use proc_macro2 :: Span ; pub use stageleft :: Quoted ; pub use super :: built :: build_inner ; pub use crate :: deploy :: { LocalDeploy , Node } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: { Cluster , ClusterSpec , Deploy , HfCompiled , Process , ProcessSpec } ; pub use crate :: builder :: deploy :: DeployFlow ; # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > Drop for DeployFlow < 'a , D > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped DeployFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > DeployFlow < 'a , D > { pub fn with_process < P > (mut self , process : & Process < P > , spec : impl ProcessSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < P > () . to_string () ; self . nodes . insert (process . id , spec . build (process . id , & tag_name)) ; self } pub fn with_cluster < C > (mut self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < C > () . to_string () ; self . clusters . insert (cluster . id , spec . build (cluster . id , & tag_name)) ; self } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployFlow < 'a , D > { pub fn compile (mut self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; let mut seen_tees : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | leaf . compile_network :: < D > (env , & mut seen_tees , & self . nodes , & self . clusters)) . collect () ; let extra_stmts = self . extra_stmts (env) ; HfCompiled { hydroflow_ir : build_inner (& mut ir_leaves_networked) , extra_stmts , _phantom : PhantomData , } } fn extra_stmts (& self , env : & < D as Deploy < 'a > > :: CompileEnv) -> BTreeMap < usize , Vec < syn :: Stmt > > { let all_locations_count = self . nodes . len () + self . clusters . len () ; let mut extra_stmts : BTreeMap < usize , Vec < syn :: Stmt > > = BTreeMap :: new () ; for & c_id in self . clusters . keys () { let self_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , c_id) , Span :: call_site () ,) ; let self_id_expr = D :: cluster_self_id (env) . splice () ; extra_stmts . entry (c_id) . or_default () . push (syn :: parse_quote ! { let # self_id_ident = # self_id_expr ; }) ; for other_location in 0 .. all_locations_count { let other_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , c_id) , Span :: call_site () ,) ; let other_id_expr = D :: cluster_ids (env , c_id) . splice () ; extra_stmts . entry (other_location) . or_default () . push (syn :: parse_quote ! { let # other_id_ident = # other_id_expr ; }) ; } } extra_stmts } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a , CompileEnv = () > > DeployFlow < 'a , D > { # [must_use] pub fn deploy (mut self , env : & mut D :: InstantiateEnv) -> DeployResult < 'a , D > { self . used = true ; let mut seen_tees_instantiate : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | { leaf . compile_network :: < D > (& () , & mut seen_tees_instantiate , & self . nodes , & self . clusters ,) }) . collect () ; let mut compiled = build_inner (& mut ir_leaves_networked) ; let mut extra_stmts = self . extra_stmts (& ()) ; let mut meta = D :: Meta :: default () ; let (mut processes , mut clusters) = (std :: mem :: take (& mut self . nodes) . into_iter () . map (| (node_id , node) | { node . instantiate (env , & mut meta , compiled . remove (& node_id) . unwrap () , extra_stmts . remove (& node_id) . unwrap_or_default () ,) ; (node_id , node) }) . collect :: < HashMap < _ , _ > > () , std :: mem :: take (& mut self . clusters) . into_iter () . map (| (cluster_id , cluster) | { cluster . instantiate (env , & mut meta , compiled . remove (& cluster_id) . unwrap () , extra_stmts . remove (& cluster_id) . unwrap_or_default () ,) ; (cluster_id , cluster) }) . collect :: < HashMap < _ , _ > > () ,) ; for node in processes . values_mut () { node . update_meta (& meta) ; } for cluster in clusters . values_mut () { cluster . update_meta (& meta) ; } let mut seen_tees_connect = HashMap :: new () ; for leaf in ir_leaves_networked { leaf . connect_network (& mut seen_tees_connect) ; } DeployResult { processes , clusters , } } } pub use crate :: builder :: deploy :: DeployResult ; # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployResult < 'a , D > { pub fn get_process < P > (& self , p : & Process < P >) -> & D :: Process { let id = match p . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . processes . get (& id) . unwrap () } pub fn get_cluster < C > (& self , c : & Cluster < C >) -> & D :: Cluster { let id = match c . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . clusters . get (& id) . unwrap () } } } # [doc = " Tracks the leaves of the dataflow IR. This is referenced by"] # [doc = " `Stream` and `HfCycle` to build the IR. The inner option will"] # [doc = " be set to `None` when this builder is finalized."] pub type FlowLeaves < 'a > = Rc < RefCell < Option < Vec < HfPlusLeaf < 'a > > > > > ; pub use crate :: builder :: ClusterIds ; # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Vec < u32 > > for ClusterIds < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , & 'a Vec < u32 > > for ClusterIds < 'a > { } # [derive (Copy , Clone)] pub struct ClusterSelfId < 'a > { pub id : usize , pub _phantom : PhantomData < & 'a mut & 'a u32 > , } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < u32 > for ClusterSelfId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , u32 > for ClusterSelfId < 'a > { } pub use crate :: builder :: FlowBuilder ; # [cfg (stageleft_macro)] impl < 'a > Drop for FlowBuilder < 'a > { fn drop (& mut self) { if ! self . finalized { panic ! ("Dropped FlowBuilder without finalizing, you may have forgotten to call `with_default_optimize`, `optimize_with`, or `finalize`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > QuotedContext for FlowBuilder < 'a > { fn create () -> Self { FlowBuilder :: new () } } # [cfg (stageleft_macro)] impl < 'a > FlowBuilder < 'a > { # [allow (clippy :: new_without_default)] pub fn new () -> FlowBuilder < 'a > { FlowBuilder { ir_leaves : Rc :: new (RefCell :: new (Some (Vec :: new ()))) , nodes : RefCell :: new (vec ! []) , clusters : RefCell :: new (vec ! []) , cycle_ids : RefCell :: new (HashMap :: new ()) , next_node_id : RefCell :: new (0) , finalized : false , _phantom : PhantomData , } } pub fn finalize (mut self) -> built :: BuiltFlow < 'a > { self . finalized = true ; built :: BuiltFlow { ir : self . ir_leaves . borrow_mut () . take () . unwrap () , processes : self . nodes . replace (vec ! []) , clusters : self . clusters . replace (vec ! []) , used : false , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> built :: BuiltFlow < 'a > { self . finalize () . with_default_optimize () } pub fn optimize_with (self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> built :: BuiltFlow < 'a > { self . finalize () . optimize_with (f) } pub fn ir_leaves (& self) -> & FlowLeaves < 'a > { & self . ir_leaves } pub fn process < P > (& self) -> Process < P > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . nodes . borrow_mut () . push (id) ; Process { id , _phantom : PhantomData , } } pub fn cluster < C > (& self) -> Cluster < C > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . clusters . borrow_mut () . push (id) ; Cluster { id , _phantom : PhantomData , } } pub fn runtime_context (& self) -> RuntimeContext < 'a > { RuntimeContext { _phantom : PhantomData , } } pub fn cluster_members < C > (& self , cluster : & Cluster < C > ,) -> impl Quoted < 'a , & 'a Vec < u32 > > + Copy + 'a { ClusterIds { id : cluster . id , _phantom : PhantomData , } } pub fn cluster_self_id < C > (& self , cluster : & Cluster < C >) -> impl Quoted < 'a , u32 > + Copy + 'a { ClusterSelfId { id : cluster . id , _phantom : PhantomData , } } pub fn spin < L : Location > (& self , on : & L) -> Stream < 'a , () , Unbounded , NoTick , L > { Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Spin () , location_kind : on . id () , })) ,) } pub fn spin_batch < L : Location > (& self , on : & L , batch_size : impl Quoted < 'a , usize > + Copy + 'a ,) -> Stream < 'a , () , Bounded , Tick , L > { self . spin (on) . flat_map (q ! (move | _ | 0 .. batch_size)) . map (q ! (| _ | ())) . tick_batch () } pub fn source_stream < T , E : FuturesStream < Item = T > + Unpin , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Unbounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Stream (e . into ()) , location_kind : on . id () , })) ,) } pub fn source_iter < T , E : IntoIterator < Item = T > , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Bounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , })) ,) } pub fn singleton < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Singleton < 'a , T , Bounded , NoTick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Singleton :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,)))) ,) } pub fn singleton_first_tick < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Optional < 'a , T , Bounded , Tick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,) } pub fn source_interval < L : Location > (& self , on : & L , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , () , Unbounded , NoTick , L > { let interval = interval . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : on . id () , })) ,) } pub fn source_interval_delayed < L : Location > (& self , on : & L , delay : impl Quoted < 'a , Duration > + Copy + 'a , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , tokio :: time :: Instant , Unbounded , NoTick , L > { self . source_stream (on , q ! (tokio_stream :: wrappers :: IntervalStream :: new (tokio :: time :: interval_at (tokio :: time :: Instant :: now () + delay , interval))) ,) . tick_batch () . first () . latest () } pub fn cycle < S : CycleCollection < 'a > > (& self , on : & S :: Location) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , on . id ()) ,) } pub fn cycle_with_initial < S : CycleCollectionWithInitial < 'a > > (& self , on : & S :: Location , initial : S ,) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , initial , on . id ()) ,) } } } pub use builder :: FlowBuilder ; pub mod ir { pub use core :: panic ; pub use std :: cell :: RefCell ; pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow_lang :: graph :: FlatGraphBuilder ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: ToTokens ; pub use syn :: parse_quote ; pub use crate :: deploy :: Deploy ; pub use crate :: location :: LocationId ; pub use crate :: ir :: DebugExpr ; # [cfg (stageleft_macro)] impl From < syn :: Expr > for DebugExpr { fn from (expr : syn :: Expr) -> DebugExpr { DebugExpr (expr) } } # [cfg (stageleft_macro)] impl Deref for DebugExpr { type Target = syn :: Expr ; fn deref (& self) -> & Self :: Target { & self . 0 } } # [cfg (stageleft_macro)] impl ToTokens for DebugExpr { fn to_tokens (& self , tokens : & mut TokenStream) { self . 0 . to_tokens (tokens) ; } } # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugExpr { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "{}" , self . 0 . to_token_stream ()) } } pub use crate :: ir :: DebugInstantiate ; # [cfg (stageleft_macro)] impl < 'a > std :: fmt :: Debug for DebugInstantiate < 'a > { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<network instantiate>") } } pub use crate :: ir :: DebugPipelineFn ; # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugPipelineFn { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<function>") } } pub use crate :: ir :: HfPlusSource ; pub use crate :: ir :: HfPlusLeaf ; # [cfg (stageleft_macro)] impl < 'a > HfPlusLeaf < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . compile_network :: < D > (compile_env , s , nodes , clusters) ; } , seen_tees ,) } pub fn connect_network (self , seen_tees : & mut SeenTees < 'a >) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . connect_network (s) ; } , seen_tees ,) } pub fn transform_children (self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) -> HfPlusLeaf < 'a > { match self { HfPlusLeaf :: ForEach { f , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: ForEach { f , input } } HfPlusLeaf :: DestSink { sink , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: DestSink { sink , input } } HfPlusLeaf :: CycleSink { ident , location_kind , mut input , } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: CycleSink { ident , location_kind , input , } } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) { match self { HfPlusLeaf :: ForEach { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> for_each (# f) ; }) ; } HfPlusLeaf :: DestSink { sink , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink) ; }) ; } HfPlusLeaf :: CycleSink { ident , location_kind , input , } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; assert_eq ! (input_location_id , * location_id , "cycle_sink location mismatch") ; graph_builders . entry (* location_id) . or_default () . add_statement (parse_quote ! { # ident = # input_ident ; }) ; } } } } pub use crate :: ir :: HfPlusNode ; pub type SeenTees < 'a > = HashMap < * const RefCell < HfPlusNode < 'a > > , Rc < RefCell < HfPlusNode < 'a > > > > ; # [cfg (stageleft_macro)] impl < 'a > HfPlusNode < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (& mut self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) { self . transform_children (| n , s | n . compile_network :: < D > (compile_env , s , nodes , clusters) , seen_tees ,) ; if let HfPlusNode :: Network { from_location , to_location , instantiate_fn , .. } = self { let (sink_expr , source_expr , connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { let ((sink , source) , connect_fn) = match (from_location , to_location) { (LocationId :: Process (from) , LocationId :: Process (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: o2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Process (from) , LocationId :: Cluster (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: o2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Process (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: m2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Cluster (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: m2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } } ; (sink , source , connect_fn) } DebugInstantiate :: Finalized (_ , _ , _) => panic ! ("network already finalized") , } ; * instantiate_fn = DebugInstantiate :: Finalized (sink_expr , source_expr , connect_fn) ; } } pub fn connect_network (& mut self , seen_tees : & mut SeenTees < 'a >) { self . transform_children (| n , s | n . connect_network (s) , seen_tees) ; if let HfPlusNode :: Network { instantiate_fn , .. } = self { match instantiate_fn { DebugInstantiate :: Building () => panic ! ("network not built") , DebugInstantiate :: Finalized (_ , _ , ref connect_fn) => { connect_fn () ; } } } } pub fn transform_children (& mut self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) { match self { HfPlusNode :: Placeholder => { panic ! () ; } HfPlusNode :: Source { .. } => { } HfPlusNode :: CycleSource { .. } => { } HfPlusNode :: Tee { inner } => { if let Some (transformed) = seen_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { * inner = transformed . clone () ; } else { let transformed_cell = Rc :: new (RefCell :: new (HfPlusNode :: Placeholder)) ; seen_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , transformed_cell . clone () ,) ; let mut orig = inner . replace (HfPlusNode :: Placeholder) ; transform (& mut orig , seen_tees) ; * transformed_cell . borrow_mut () = orig ; * inner = transformed_cell ; } } HfPlusNode :: Persist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Unpersist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Delta (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Union (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossProduct (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossSingleton (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Join (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Difference (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: AntiJoin (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Map { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FlatMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Filter { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FilterMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Sort (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: DeferTick (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Enumerate (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Inspect { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Unique (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Fold { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FoldKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Reduce { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: ReduceKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Network { input , .. } => { transform (input . as_mut () , seen_tees) ; } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) -> (syn :: Ident , usize) { match self { HfPlusNode :: Placeholder => { panic ! () } HfPlusNode :: Persist (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let persist_id = * next_stmt_id ; * next_stmt_id += 1 ; let persist_ident = syn :: Ident :: new (& format ! ("stream_{}" , persist_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # persist_ident = # inner_ident -> persist ::<'static > () ; }) ; (persist_ident , location) } HfPlusNode :: Unpersist (_) => { panic ! ("Unpersist is a marker node and should have been optimized away. This is likely a compiler bug.") } HfPlusNode :: Delta (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let delta_id = * next_stmt_id ; * next_stmt_id += 1 ; let delta_ident = syn :: Ident :: new (& format ! ("stream_{}" , delta_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # delta_ident = # inner_ident -> multiset_delta () ; }) ; (delta_ident , location) } HfPlusNode :: Source { source , location_kind , } => { let source_id = * next_stmt_id ; * next_stmt_id += 1 ; let source_ident = syn :: Ident :: new (& format ! ("stream_{}" , source_id) , Span :: call_site ()) ; let source_stmt = match source { HfPlusSource :: Stream (expr) => { parse_quote ! { # source_ident = source_stream (# expr) ; } } HfPlusSource :: Iter (expr) => { parse_quote ! { # source_ident = source_iter (# expr) ; } } HfPlusSource :: Interval (expr) => { parse_quote ! { # source_ident = source_interval (# expr) ; } } HfPlusSource :: Spin () => { parse_quote ! { # source_ident = spin () ; } } } ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; graph_builders . entry (* location_id) . or_default () . add_statement (source_stmt) ; (source_ident , * location_id) } HfPlusNode :: CycleSource { ident , location_kind , } => { let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; (ident . clone () , * location_id) } HfPlusNode :: Tee { inner } => { if let Some (ret) = built_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { ret . clone () } else { let (inner_ident , inner_location_id) = inner . borrow () . emit (graph_builders , built_tees , next_stmt_id) ; let tee_id = * next_stmt_id ; * next_stmt_id += 1 ; let tee_ident = syn :: Ident :: new (& format ! ("stream_{}" , tee_id) , Span :: call_site ()) ; let builder = graph_builders . entry (inner_location_id) . or_default () ; builder . add_statement (parse_quote ! { # tee_ident = # inner_ident -> tee () ; }) ; built_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , (tee_ident . clone () , inner_location_id) ,) ; (tee_ident , inner_location_id) } } HfPlusNode :: Union (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "union inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let union_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # union_ident = union () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [0] # union_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # union_ident ; }) ; (union_ident , left_location_id) } HfPlusNode :: CrossSingleton (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "cross_singleton inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let cross_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # cross_ident = cross_singleton () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [input] # cross_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [single] # cross_ident ; }) ; (cross_ident , left_location_id) } HfPlusNode :: CrossProduct (..) | HfPlusNode :: Join (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: CrossProduct (..)) { parse_quote ! (cross_join_multiset) } else { parse_quote ! (join_multiset) } ; let (HfPlusNode :: CrossProduct (left , right) | HfPlusNode :: Join (left , right)) = self else { unreachable ! () } ; let (left_inner , left_was_persist) = if let HfPlusNode :: Persist (left) = left . as_ref () { (left , true) } else { (left , false) } ; let (right_inner , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left_inner . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right_inner . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "join / cross product inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; match (left_was_persist , right_was_persist) { (true , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'static > () ; }) ; } (true , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'tick > () ; }) ; } (false , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } (false , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } } ; builder . add_statement (parse_quote ! { # left_ident -> [0] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Difference (..) | HfPlusNode :: AntiJoin (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Difference (..)) { parse_quote ! (difference_multiset) } else { parse_quote ! (anti_join_multiset) } ; let (HfPlusNode :: Difference (left , right) | HfPlusNode :: AntiJoin (left , right)) = self else { unreachable ! () } ; let (right , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "difference / anti join inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; if right_was_persist { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } else { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } builder . add_statement (parse_quote ! { # left_ident -> [pos] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [neg] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Map { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let map_id = * next_stmt_id ; * next_stmt_id += 1 ; let map_ident = syn :: Ident :: new (& format ! ("stream_{}" , map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # map_ident = # input_ident -> map (# f) ; }) ; (map_ident , input_location_id) } HfPlusNode :: FlatMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let flat_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let flat_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , flat_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # flat_map_ident = # input_ident -> flat_map (# f) ; }) ; (flat_map_ident , input_location_id) } HfPlusNode :: Filter { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_ident = # input_ident -> filter (# f) ; }) ; (filter_ident , input_location_id) } HfPlusNode :: FilterMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_map_ident = # input_ident -> filter_map (# f) ; }) ; (filter_map_ident , input_location_id) } HfPlusNode :: Sort (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sort_id = * next_stmt_id ; * next_stmt_id += 1 ; let sort_ident = syn :: Ident :: new (& format ! ("stream_{}" , sort_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # sort_ident = # input_ident -> sort () ; }) ; (sort_ident , input_location_id) } HfPlusNode :: DeferTick (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let defer_tick_id = * next_stmt_id ; * next_stmt_id += 1 ; let defer_tick_ident = syn :: Ident :: new (& format ! ("stream_{}" , defer_tick_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # defer_tick_ident = # input_ident -> defer_tick_lazy () ; }) ; (defer_tick_ident , input_location_id) } HfPlusNode :: Enumerate (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let enumerate_id = * next_stmt_id ; * next_stmt_id += 1 ; let enumerate_ident = syn :: Ident :: new (& format ! ("stream_{}" , enumerate_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # enumerate_ident = # input_ident -> enumerate () ; }) ; (enumerate_ident , input_location_id) } HfPlusNode :: Inspect { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let inspect_id = * next_stmt_id ; * next_stmt_id += 1 ; let inspect_ident = syn :: Ident :: new (& format ! ("stream_{}" , inspect_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # inspect_ident = # input_ident -> inspect (# f) ; }) ; (inspect_ident , input_location_id) } HfPlusNode :: Unique (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let unique_id = * next_stmt_id ; * next_stmt_id += 1 ; let unique_ident = syn :: Ident :: new (& format ! ("stream_{}" , unique_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # unique_ident = # input_ident -> unique ::<'tick > () ; }) ; (unique_ident , input_location_id) } HfPlusNode :: Fold { .. } | HfPlusNode :: FoldKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Fold { .. }) { parse_quote ! (fold) } else { parse_quote ! (fold_keyed) } ; let (HfPlusNode :: Fold { init , acc , input } | HfPlusNode :: FoldKeyed { init , acc , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let fold_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'static > (# init , # acc) ; }) ; } else { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'tick > (# init , # acc) ; }) ; } (fold_ident , input_location_id) } HfPlusNode :: Reduce { .. } | HfPlusNode :: ReduceKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Reduce { .. }) { parse_quote ! (reduce) } else { parse_quote ! (reduce_keyed) } ; let (HfPlusNode :: Reduce { f , input } | HfPlusNode :: ReduceKeyed { f , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let reduce_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'static > (# f) ; }) ; } else { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'tick > (# f) ; }) ; } (reduce_ident , input_location_id) } HfPlusNode :: Network { from_location : _ , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input , } => { let (sink_expr , source_expr , _connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { panic ! ("Expected the network to be finalized") } DebugInstantiate :: Finalized (sink , source , connect_fn) => { (sink , source , connect_fn) } } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sender_builder = graph_builders . entry (input_location_id) . or_default () ; if let Some (serialize_pipeline) = serialize_pipeline { sender_builder . add_statement (parse_quote ! { # input_ident -> # serialize_pipeline -> dest_sink (# sink_expr) ; }) ; } else { sender_builder . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink_expr) ; }) ; } let to_id = match to_location { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let receiver_builder = graph_builders . entry (* to_id) . or_default () ; let receiver_stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let receiver_stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , receiver_stream_id) , Span :: call_site ()) ; if let Some (deserialize_pipeline) = deserialize_pipeline { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) -> # deserialize_pipeline ; }) ; } else { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) ; }) ; } (receiver_stream_ident , * to_id) } } } } } pub mod persist_pullup { pub use std :: cell :: RefCell ; pub use std :: collections :: HashSet ; pub use std :: ops :: Deref ; pub use crate :: ir :: * ; pub fn persist_pullup_node < 'a > (node : & mut HfPlusNode < 'a > , seen_tees : & mut SeenTees < 'a > , persist_pulled_tees : & mut HashSet < * const RefCell < HfPlusNode < 'a > > > ,) { node . transform_children (| n , s | persist_pullup_node (n , s , persist_pulled_tees) , seen_tees ,) ; match node { HfPlusNode :: Unpersist (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Unpersist (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Delta (HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Delta (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Tee { inner } => { if persist_pulled_tees . contains (& (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >)) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } else { let inner_borrow = inner . borrow () ; if let HfPlusNode :: Persist (_) = inner_borrow . deref () { drop (inner_borrow) ; persist_pulled_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >) ; if let HfPlusNode :: Persist (box behind_persist) = inner . replace (HfPlusNode :: Placeholder) { * inner . borrow_mut () = behind_persist ; } else { unreachable ! () } * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } } } HfPlusNode :: Map { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Map { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Map { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: FlatMap { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: FlatMap { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: FlatMap { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Filter { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Filter { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Filter { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Network { input : box HfPlusNode :: Persist (_) , .. } => { if let HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Union (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Union (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Union (left , right))) ; } else { unreachable ! () } } HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: CrossProduct (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,) ,)))) ; } else { unreachable ! () } } HfPlusNode :: Join (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Join (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: Join (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,))))) ; } else { unreachable ! () } } _ => { } } } pub fn persist_pullup (ir : Vec < HfPlusLeaf >) -> Vec < HfPlusLeaf > { let mut seen_tees = Default :: default () ; let mut persist_pulled_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| n , s | persist_pullup_node (n , s , & mut persist_pulled_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn persist_pullup_through_map () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } # [test] fn persist_pullup_behind_tee () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; let before_tee = flow . source_iter (& process , q ! (0 .. 10)) . tick_batch () . persist () ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } } } pub mod profiler { pub use std :: cell :: RefCell ; pub use hydroflow :: futures :: channel :: mpsc :: UnboundedSender ; pub use stageleft :: * ; pub use crate as hydroflow_plus ; pub use crate :: ir :: * ; pub use crate :: RuntimeContext ; pub fn increment_counter (count : & mut u64) { * count += 1 ; } pub fn quoted_any_fn < 'a , F : Fn (& usize) + 'a , Q : IntoQuotedMut < 'a , F > > (q : Q) -> Q { q } # [doc = " Add a profiling node before each node to count the cardinality of its input"] pub fn add_profiling_node < 'a > (node : & mut HfPlusNode < 'a > , _context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > , id : & mut u32 , seen_tees : & mut SeenTees < 'a > ,) { let my_id = * id ; * id += 1 ; node . transform_children (| node , seen_tees | { add_profiling_node (node , _context , counters , counter_queue , id , seen_tees) } , seen_tees ,) ; let orig_node = std :: mem :: replace (node , HfPlusNode :: Placeholder) ; * node = HfPlusNode :: Inspect { f : quoted_any_fn (q ! ({ counter_queue . borrow () . unbounded_send ((my_id as usize , counters . borrow () [my_id as usize])) . unwrap () ; counters . borrow_mut () [my_id as usize] = 0 ; move | _ | { hydroflow_plus :: profiler :: increment_counter (& mut counters . borrow_mut () [my_id as usize] ,) ; } })) . splice () . into () , input : Box :: new (orig_node) , } } # [doc = " Count the cardinality of each input and periodically output to a file"] pub fn profiling < 'a > (ir : Vec < HfPlusLeaf < 'a > > , context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > ,) -> Vec < HfPlusLeaf < 'a > > { let mut id = 0 ; let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | { add_profiling_node (node , context , counters , counter_queue , & mut id , seen_tees) } , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn profiler_wrapping_all_operators () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let runtime_context = flow . runtime_context () ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (& built . ir ()) ; let counters = RuntimeData :: new ("Fake") ; let counter_queue = RuntimeData :: new ("Fake") ; let pushed_down = built . with_default_optimize () . optimize_with (| ir | super :: profiling (ir , runtime_context , counters , counter_queue)) ; insta :: assert_debug_snapshot ! (& pushed_down . ir ()) ; let _ = pushed_down . compile_no_network :: < MultiGraph > () ; } } } pub mod properties { pub use std :: collections :: HashSet ; pub use stageleft :: * ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , SeenTees } ; pub use crate :: properties :: PropertyDatabase ; # [doc = " Allows us to convert the hydroflow datatype for folds to a binary operation for the algebra"] # [doc = " property tests."] # [allow (dead_code)] pub fn convert_hf_to_binary < I , A : Default , F : Fn (& mut A , I) > (f : F) -> impl Fn (I , I) -> A { move | a , b | { let mut acc = Default :: default () ; f (& mut acc , a) ; f (& mut acc , b) ; acc } } # [cfg (stageleft_macro)] impl PropertyDatabase { # [doc = " Tags the expression as commutative."] pub fn add_commutative_tag < 'a , I , A , F : Fn (& mut A , I) , Q : Quoted < 'a , F > + Clone > (& mut self , expr : Q ,) -> Q { let expr_clone = expr . clone () ; self . commutative . insert (expr_clone . splice ()) ; expr } pub fn is_tagged_commutative (& self , expr : & syn :: Expr) -> bool { self . commutative . contains (expr) } } pub fn properties_optimize_node < 'a > (node : & mut HfPlusNode < 'a > , db : & PropertyDatabase , seen_tees : & mut SeenTees < 'a > ,) { node . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , seen_tees ,) ; match node { HfPlusNode :: ReduceKeyed { f , .. } if db . is_tagged_commutative (& f . 0) => { dbg ! ("IDENTIFIED COMMUTATIVE OPTIMIZATION for {:?}" , & f) ; } _ => { } } } pub fn properties_optimize < 'a > (ir : Vec < HfPlusLeaf < 'a > > , db : & PropertyDatabase ,) -> Vec < HfPlusLeaf < 'a > > { let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use super :: * ; use crate :: deploy :: SingleProcessGraph ; use crate :: FlowBuilder ; # [test] fn test_property_database () { let mut db = PropertyDatabase :: default () ; assert ! (! db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; let _ = db . add_commutative_tag (q ! (| a : & mut i32 , b : i32 | * a += b)) ; assert ! (db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; } # [test] fn test_property_optimized () { let flow = FlowBuilder :: new () ; let mut database = PropertyDatabase :: default () ; let process = flow . process :: < () > () ; let counter_func = q ! (| count : & mut i32 , _ | * count += 1) ; let _ = database . add_commutative_tag (counter_func) ; flow . source_iter (& process , q ! (vec ! [])) . map (q ! (| string : String | (string , ()))) . tick_batch () . fold_keyed (q ! (|| 0) , counter_func) . all_ticks () . for_each (q ! (| (string , count) | println ! ("{}: {}" , string , count))) ; let built = flow . finalize () . optimize_with (| ir | properties_optimize (ir , & database)) . with_default_optimize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let _ = built . compile_no_network :: < SingleProcessGraph > () ; } } } pub use crate :: RuntimeContext ; # [cfg (stageleft_macro)] impl Copy for RuntimeContext < '_ > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Context > for RuntimeContext < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (quote ! (& context))) } } pub use crate :: HfCompiled ; # [cfg (stageleft_macro)] impl < 'a , ID > HfCompiled < 'a , ID > { pub fn hydroflow_ir (& self) -> & BTreeMap < usize , HydroflowGraph > { & self . hydroflow_ir } } # [cfg (stageleft_macro)] impl < 'a > HfCompiled < 'a , usize > { pub fn with_dynamic_id (self , id : impl Quoted < 'a , usize >) -> HfBuiltWithId < 'a > { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; let mut conditioned_tokens = None ; for (subgraph_id , flat_graph) in self . hydroflow_ir { let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; let my_extra_stmts = self . extra_stmts . get (& subgraph_id) . cloned () . unwrap_or_default () ; if let Some (conditioned_tokens) = conditioned_tokens . as_mut () { * conditioned_tokens = syn :: parse_quote ! { # conditioned_tokens else if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } } ; } else { conditioned_tokens = Some (syn :: parse_quote ! { if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } }) ; } } let conditioned_tokens : TokenStream = conditioned_tokens . unwrap () ; let id = id . splice () ; HfBuiltWithId { tokens : syn :: parse_quote ! ({ let __given_id = # id ; # conditioned_tokens else { panic ! ("Invalid node id: {}" , __given_id) ; } }) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfCompiled < 'a , () > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfCompiled < 'a , () > { fn to_tokens (mut self) -> (Option < TokenStream > , Option < TokenStream >) { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; if self . hydroflow_ir . len () != 1 { panic ! ("Expected exactly one subgraph in the Hydroflow IR") ; } let flat_graph = self . hydroflow_ir . remove (& 0) . unwrap () ; let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; (None , Some (tokens)) } } pub use crate :: HfBuiltWithId ; # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfBuiltWithId < 'a > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfBuiltWithId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (self . tokens)) } }
[INFO] [stdout]   |
[INFO] [stdout] help: ...otherwise replace it with an invocation of macro `deref`
[INFO] [stdout]   |
[INFO] [stdout] 1 - pub use std :: collections :: BTreeMap ; pub use std :: marker :: PhantomData ; pub use hydroflow :: scheduled :: context :: Context ; pub use hydroflow :: scheduled :: graph :: Hydroflow ; pub use hydroflow :: * ; pub use lang :: graph :: { partition_graph , HydroflowGraph } ; pub use proc_macro2 :: TokenStream ; pub use quote :: quote ; pub use stageleft :: runtime_support :: FreeVariable ; pub use stageleft :: Quoted ; pub mod runtime_support { pub use bincode ; } pub mod stream { pub use std :: cell :: RefCell ; pub use std :: hash :: Hash ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow :: bytes :: Bytes ; pub use hydroflow :: futures :: Sink ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: quote ; pub use serde :: de :: DeserializeOwned ; pub use serde :: Serialize ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use syn :: parse_quote ; pub use crate :: builder :: { ClusterIds , FlowLeaves } ; pub use crate :: cycle :: { CycleCollection , CycleComplete } ; pub use crate :: ir :: { DebugInstantiate , HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { CanSend , Location , LocationId } ; pub use crate :: { Cluster , Optional , Singleton } ; pub use crate :: stream :: Unbounded ; pub use crate :: stream :: Bounded ; pub use crate :: stream :: NoTick ; pub use crate :: stream :: Tick ; pub use crate :: stream :: Stream ; # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Stream { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Stream < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Stream { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , C , N > > ,) -> Stream < 'a , (T , O) , W , C , N > where O : Clone , { let other : Optional < 'a , O , Bounded , C , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn cross_product < O > (self , other : Stream < 'a , O , W , C , N >) -> Stream < 'a , (T , O) , W , C , N > where T : Clone , O : Clone , { if self . location_kind != other . location_kind { panic ! ("cross_product must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossProduct (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn union (self , other : Stream < 'a , T , W , C , N >) -> Stream < 'a , T , W , C , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn dest_sink < S : Unpin + Sink < T > + 'a > (self , sink : impl Quoted < 'a , S >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: DestSink { sink : sink . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn first (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } # [doc = " Allow this stream through if the other stream has elements, otherwise the output is empty."] pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } # [doc = " Allow this stream through if the other stream is empty, otherwise the output is empty."] pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn enumerate (self) -> Stream < 'a , (usize , T) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Enumerate (Box :: new (self . ir_node . into_inner ())) ,) } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn sort (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Ord , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Sort (Box :: new (self . ir_node . into_inner ())) ,) } pub fn count (self) -> Singleton < 'a , usize , Bounded , Tick , N > { self . fold (q ! (|| 0usize) , q ! (| count , _ | * count += 1)) } pub fn delta (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } pub fn unique (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Eq + Hash , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unique (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn tick_batch (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_prefix (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { self . tick_batch () . persist () } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn for_each < F : Fn (T) + 'a > (self , f : impl IntoQuotedMut < 'a , F >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: ForEach { input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , f : f . splice () . into () , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Unbounded , NoTick , N > { pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . tick_batch () . continue_if (samples . first ()) . all_ticks () } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Unbounded , NoTick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , C , N : Location > Stream < 'a , T , Bounded , C , N > { pub fn filter_not_in (self , other : Stream < 'a , T , Bounded , C , N >) -> Stream < 'a , T , Bounded , C , N > where T : Eq + Hash , { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Difference (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Stream < 'a , & T , W , C , N > { pub fn cloned (self) -> Stream < 'a , T , W , C , N > { self . map (q ! (| d | d . clone ())) } } # [cfg (stageleft_macro)] impl < 'a , K , V1 , W , C , N : Location > Stream < 'a , (K , V1) , W , C , N > { pub fn join < W2 , V2 > (self , n : Stream < 'a , (K , V2) , W2 , C , N > ,) -> Stream < 'a , (K , (V1 , V2)) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Join (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } pub fn anti_join < W2 > (self , n : Stream < 'a , K , W2 , C , N >) -> Stream < 'a , (K , V1) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("anti_join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: AntiJoin (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , K : Eq + Hash , V , N : Location > Stream < 'a , (K , V) , Bounded , Tick , N > { pub fn fold_keyed < A , I : Fn () -> A + 'a , F : Fn (& mut A , V) + 'a > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , A) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FoldKeyed { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce_keyed < F : Fn (& mut V , V) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , V) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: ReduceKeyed { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } pub fn get_this_crate () -> TokenStream { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , Span :: call_site ()) ; quote ! { # ident } } } } pub fn serialize_bincode < T : Serialize > (is_demux : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if is_demux { parse_quote ! { map (| (id , data) | { (id , # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into ()) }) } } else { parse_quote ! { map (| data | { # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into () }) } } } pub fn deserialize_bincode < T : DeserializeOwned > (tagged : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if tagged { parse_quote ! { map (| res | { let (id , b) = res . unwrap () ; (id , # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& b) . unwrap ()) }) } } else { parse_quote ! { map (| res | { # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& res . unwrap ()) . unwrap () }) } } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn send_bincode < N2 : Location , CoreType > (self , other : & N2 ,) -> Stream < 'a , N :: Out < CoreType > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T > , CoreType : Serialize + DeserializeOwned , { let serialize_pipeline = Some (serialize_bincode :: < CoreType > (N :: is_demux ())) ; let deserialize_pipeline = Some (deserialize_bincode :: < CoreType > (N :: is_tagged ())) ; Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bytes < N2 : Location > (self , other : & N2 ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T > , { Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline : None , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline : if N :: is_tagged () { Some (parse_quote ! (map (| (id , b) | (id , b . unwrap () . freeze ())))) } else { Some (parse_quote ! (map (| b | b . unwrap () . freeze ()))) } , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bincode_interleaved < N2 : Location , Tag , CoreType > (self , other : & N2 ,) -> Stream < 'a , CoreType , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T , Out < CoreType > = (Tag , CoreType) > , CoreType : Serialize + DeserializeOwned , { self . send_bincode :: < N2 , CoreType > (other) . map (q ! (| (_ , b) | b)) } pub fn send_bytes_interleaved < N2 : Location , Tag > (self , other : & N2 ,) -> Stream < 'a , Bytes , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T , Out < Bytes > = (Tag , Bytes) > , { self . send_bytes :: < N2 > (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bincode < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < T > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) > , T : Clone + Serialize + DeserializeOwned , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bincode (other) } pub fn broadcast_bincode_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , T , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) , Out < T > = (Tag , T) > + 'a , T : Clone + Serialize + DeserializeOwned , { self . broadcast_bincode (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bytes < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) > + 'a , T : Clone , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bytes (other) } pub fn broadcast_bytes_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , Bytes , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) , Out < Bytes > = (Tag , Bytes) > + 'a , T : Clone , { self . broadcast_bytes (other) . map (q ! (| (_ , b) | b)) } } } pub use stream :: { Bounded , NoTick , Stream , Tick , Unbounded } ; pub mod singleton { pub use std :: cell :: RefCell ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use crate :: builder :: FlowLeaves ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial , CycleComplete } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: Stream ; pub use crate :: singleton :: CrossResult ; # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Singleton < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Singleton :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } pub use crate :: singleton :: Singleton ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Singleton { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleComplete < 'a > for Singleton < 'a , T , Bounded , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleCollectionWithInitial < 'a > for Singleton < 'a , T , Bounded , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , initial : Self , l : LocationId ,) -> Self { Singleton :: new (l , ir_leaves , HfPlusNode :: Union (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , }) , initial . ir_node . into_inner () . into () ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Singleton < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Singleton { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , U , W , C , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (Self :: other_ir_node (other)) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Singleton < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CrossSingleton (Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , Box :: new (HfPlusNode :: Unpersist (Box :: new (Self :: other_ir_node (other)))) ,))) ,) } } pub use crate :: singleton :: Optional ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Optional { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } pub fn some (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: new (singleton . location_kind , singleton . ir_leaves , singleton . ir_node . into_inner () ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > From < Singleton < 'a , T , W , C , N > > for Optional < 'a , T , W , C , N > { fn from (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: some (singleton) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Optional < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Optional { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn into_stream (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , Tick , N > > ,) -> Optional < 'a , (T , O) , Bounded , Tick , N > where O : Clone , { let other : Optional < 'a , O , Bounded , Tick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn union (self , other : Optional < 'a , T , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Optional < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_samples (self) -> Stream < 'a , T , Unbounded , NoTick , N > { self . latest_tick () . all_ticks () } pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . latest_tick () . continue_if (samples . first ()) . latest () . tick_samples () } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Unbounded , NoTick , N > > ,) -> Optional < 'a , (T , O) , Unbounded , NoTick , N > where O : Clone , { let other : Optional < 'a , O , Unbounded , NoTick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } self . latest_tick () . cross_singleton (other . latest_tick ()) . latest () } } } pub use singleton :: { Optional , Singleton } ; pub mod location { pub use std :: marker :: PhantomData ; pub use crate :: location :: LocationId ; pub use crate :: location :: Location ; pub use crate :: location :: Process ; # [cfg (stageleft_macro)] impl < P > Clone for Process < P > { fn clone (& self) -> Self { Process { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < P > Location for Process < P > { fn id (& self) -> LocationId { LocationId :: Process (self . id) } } pub use crate :: location :: Cluster ; # [cfg (stageleft_macro)] impl < C > Clone for Cluster < C > { fn clone (& self) -> Self { Cluster { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < C > Location for Cluster < C > { fn id (& self) -> LocationId { LocationId :: Cluster (self . id) } } pub use crate :: location :: CanSend ; # [cfg (stageleft_macro)] impl < P1 , P2 > CanSend < Process < P2 > > for Process < P1 > { type In < T > = T ; type Out < T > = T ; fn is_demux () -> bool { false } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < P1 , C2 > CanSend < Cluster < C2 > > for Process < P1 > { type In < T > = (u32 , T) ; type Out < T > = T ; fn is_demux () -> bool { true } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < C1 , P2 > CanSend < Process < P2 > > for Cluster < C1 > { type In < T > = T ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { false } fn is_tagged () -> bool { true } } # [cfg (stageleft_macro)] impl < C1 , C2 > CanSend < Cluster < C2 > > for Cluster < C1 > { type In < T > = (u32 , T) ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { true } fn is_tagged () -> bool { true } } } pub use location :: { Cluster , Process } ; pub mod deploy { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use stageleft :: Quoted ; pub mod graphs { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use super :: { LocalDeploy , Node , ProcessSpec } ; pub use crate :: deploy :: graphs :: SingleProcessGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for SingleProcessGraph { type Process = SingleNode ; type Cluster = SingleNode ; type Meta = () ; type GraphId = () ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { SingleNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { SingleNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , SingleProcessGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> SingleNode { SingleNode { } } } pub use crate :: deploy :: graphs :: SingleNode ; # [cfg (stageleft_macro)] impl Node for SingleNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } pub use crate :: deploy :: graphs :: MultiGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for MultiGraph { type Process = MultiNode ; type Cluster = MultiNode ; type Meta = () ; type GraphId = usize ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { MultiNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { MultiNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , MultiGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> MultiNode { MultiNode { } } } pub use crate :: deploy :: graphs :: MultiNode ; # [cfg (stageleft_macro)] impl Node for MultiNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } } pub use graphs :: * ; pub use crate :: deploy :: LocalDeploy ; pub use crate :: deploy :: Deploy ; # [cfg (stageleft_macro)] impl < 'a , T : Deploy < 'a , Process = N , Cluster = C , Meta = M , GraphId = R > , N : Node < Meta = M > , C : Node < Meta = M > , M : Default , R , > LocalDeploy < 'a > for T { type Process = N ; type Cluster = C ; type Meta = M ; type GraphId = R ; fn has_trivial_node () -> bool { < T as Deploy < 'a > > :: has_trivial_node () } fn trivial_process (id : usize) -> Self :: Process { < T as Deploy < 'a > > :: trivial_process (id) } fn trivial_cluster (id : usize) -> Self :: Cluster { < T as Deploy < 'a > > :: trivail_cluster (id) } } pub use crate :: deploy :: ProcessSpec ; pub use crate :: deploy :: ClusterSpec ; pub use crate :: deploy :: Node ; } pub use deploy :: { ClusterSpec , Deploy , ProcessSpec } ; pub mod cycle { pub use std :: marker :: PhantomData ; pub use crate :: builder :: FlowLeaves ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: cycle :: CycleComplete ; pub use crate :: cycle :: CycleCollection ; pub use crate :: cycle :: CycleCollectionWithInitial ; pub use crate :: cycle :: HfCycle ; # [cfg (stageleft_macro)] impl < 'a , S : CycleComplete < 'a > > HfCycle < 'a , S > { pub fn complete (self , stream : S) { let ident = self . ident ; S :: complete (stream , ident) } } } pub use cycle :: HfCycle ; pub mod builder { pub use std :: cell :: RefCell ; pub use std :: collections :: HashMap ; pub use std :: marker :: PhantomData ; pub use std :: rc :: Rc ; pub use std :: time :: Duration ; pub use hydroflow :: futures :: stream :: Stream as FuturesStream ; pub use hydroflow :: { tokio , tokio_stream } ; pub use internal :: TokenStream ; pub use proc_macro2 :: Span ; pub use quote :: quote ; pub use runtime_support :: FreeVariable ; pub use stageleft :: * ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Cluster , Location , LocationId , Process } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: { HfCycle , Optional , RuntimeContext , Singleton , Stream } ; pub mod built { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use hydroflow_lang :: graph :: { eliminate_extra_unions_tees , HydroflowGraph } ; pub use super :: deploy :: { DeployFlow , DeployResult } ; pub use crate :: deploy :: { ClusterSpec , Deploy , LocalDeploy , ProcessSpec } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Cluster , Process } ; pub use crate :: HfCompiled ; pub use crate :: builder :: built :: BuiltFlow ; # [cfg (stageleft_macro)] impl < 'a > Drop for BuiltFlow < 'a > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped BuiltFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn ir (& self) -> & Vec < HfPlusLeaf < 'a > > { & self . ir } pub fn optimize_with (mut self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> BuiltFlow < 'a > { self . used = true ; BuiltFlow { ir : f (std :: mem :: take (& mut self . ir)) , processes : std :: mem :: take (& mut self . processes) , clusters : std :: mem :: take (& mut self . clusters) , used : false , _phantom : PhantomData , } } } pub fn build_inner (ir : & mut Vec < HfPlusLeaf >) -> BTreeMap < usize , HydroflowGraph > { let mut builders = BTreeMap :: new () ; let mut built_tees = HashMap :: new () ; let mut next_stmt_id = 0 ; for leaf in ir { leaf . emit (& mut builders , & mut built_tees , & mut next_stmt_id) ; } builders . into_iter () . map (| (k , v) | { let (mut flat_graph , _ , _) = v . build () ; eliminate_extra_unions_tees (& mut flat_graph) ; (k , flat_graph) }) . collect () } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn compile_no_network < D : LocalDeploy < 'a > > (mut self) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; HfCompiled { hydroflow_ir : build_inner (& mut self . ir) , extra_stmts : BTreeMap :: new () , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> BuiltFlow < 'a > { self . optimize_with (crate :: persist_pullup :: persist_pullup) } fn into_deploy < D : LocalDeploy < 'a > > (mut self) -> DeployFlow < 'a , D > { self . used = true ; let processes = if D :: has_trivial_node () { self . processes . iter () . map (| id | (* id , D :: trivial_process (* id))) . collect () } else { HashMap :: new () } ; let clusters = if D :: has_trivial_node () { self . clusters . iter () . map (| id | (* id , D :: trivial_cluster (* id))) . collect () } else { HashMap :: new () } ; DeployFlow { ir : std :: mem :: take (& mut self . ir) , nodes : processes , clusters , used : false , _phantom : PhantomData , } } pub fn with_process < P , D : LocalDeploy < 'a > > (self , process : & Process < P > , spec : impl ProcessSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_process (process , spec) } pub fn with_cluster < C , D : LocalDeploy < 'a > > (self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_cluster (cluster , spec) } pub fn compile < D : Deploy < 'a > + 'a > (self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . into_deploy :: < D > () . compile (env) } pub fn deploy < D : Deploy < 'a , CompileEnv = () > + 'a > (self , env : & mut D :: InstantiateEnv ,) -> DeployResult < 'a , D > { self . into_deploy :: < D > () . deploy (env) } } } pub mod deploy { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use proc_macro2 :: Span ; pub use stageleft :: Quoted ; pub use super :: built :: build_inner ; pub use crate :: deploy :: { LocalDeploy , Node } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: { Cluster , ClusterSpec , Deploy , HfCompiled , Process , ProcessSpec } ; pub use crate :: builder :: deploy :: DeployFlow ; # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > Drop for DeployFlow < 'a , D > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped DeployFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > DeployFlow < 'a , D > { pub fn with_process < P > (mut self , process : & Process < P > , spec : impl ProcessSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < P > () . to_string () ; self . nodes . insert (process . id , spec . build (process . id , & tag_name)) ; self } pub fn with_cluster < C > (mut self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < C > () . to_string () ; self . clusters . insert (cluster . id , spec . build (cluster . id , & tag_name)) ; self } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployFlow < 'a , D > { pub fn compile (mut self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; let mut seen_tees : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | leaf . compile_network :: < D > (env , & mut seen_tees , & self . nodes , & self . clusters)) . collect () ; let extra_stmts = self . extra_stmts (env) ; HfCompiled { hydroflow_ir : build_inner (& mut ir_leaves_networked) , extra_stmts , _phantom : PhantomData , } } fn extra_stmts (& self , env : & < D as Deploy < 'a > > :: CompileEnv) -> BTreeMap < usize , Vec < syn :: Stmt > > { let all_locations_count = self . nodes . len () + self . clusters . len () ; let mut extra_stmts : BTreeMap < usize , Vec < syn :: Stmt > > = BTreeMap :: new () ; for & c_id in self . clusters . keys () { let self_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , c_id) , Span :: call_site () ,) ; let self_id_expr = D :: cluster_self_id (env) . splice () ; extra_stmts . entry (c_id) . or_default () . push (syn :: parse_quote ! { let # self_id_ident = # self_id_expr ; }) ; for other_location in 0 .. all_locations_count { let other_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , c_id) , Span :: call_site () ,) ; let other_id_expr = D :: cluster_ids (env , c_id) . splice () ; extra_stmts . entry (other_location) . or_default () . push (syn :: parse_quote ! { let # other_id_ident = # other_id_expr ; }) ; } } extra_stmts } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a , CompileEnv = () > > DeployFlow < 'a , D > { # [must_use] pub fn deploy (mut self , env : & mut D :: InstantiateEnv) -> DeployResult < 'a , D > { self . used = true ; let mut seen_tees_instantiate : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | { leaf . compile_network :: < D > (& () , & mut seen_tees_instantiate , & self . nodes , & self . clusters ,) }) . collect () ; let mut compiled = build_inner (& mut ir_leaves_networked) ; let mut extra_stmts = self . extra_stmts (& ()) ; let mut meta = D :: Meta :: default () ; let (mut processes , mut clusters) = (std :: mem :: take (& mut self . nodes) . into_iter () . map (| (node_id , node) | { node . instantiate (env , & mut meta , compiled . remove (& node_id) . unwrap () , extra_stmts . remove (& node_id) . unwrap_or_default () ,) ; (node_id , node) }) . collect :: < HashMap < _ , _ > > () , std :: mem :: take (& mut self . clusters) . into_iter () . map (| (cluster_id , cluster) | { cluster . instantiate (env , & mut meta , compiled . remove (& cluster_id) . unwrap () , extra_stmts . remove (& cluster_id) . unwrap_or_default () ,) ; (cluster_id , cluster) }) . collect :: < HashMap < _ , _ > > () ,) ; for node in processes . values_mut () { node . update_meta (& meta) ; } for cluster in clusters . values_mut () { cluster . update_meta (& meta) ; } let mut seen_tees_connect = HashMap :: new () ; for leaf in ir_leaves_networked { leaf . connect_network (& mut seen_tees_connect) ; } DeployResult { processes , clusters , } } } pub use crate :: builder :: deploy :: DeployResult ; # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployResult < 'a , D > { pub fn get_process < P > (& self , p : & Process < P >) -> & D :: Process { let id = match p . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . processes . get (& id) . unwrap () } pub fn get_cluster < C > (& self , c : & Cluster < C >) -> & D :: Cluster { let id = match c . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . clusters . get (& id) . unwrap () } } } # [doc = " Tracks the leaves of the dataflow IR. This is referenced by"] # [doc = " `Stream` and `HfCycle` to build the IR. The inner option will"] # [doc = " be set to `None` when this builder is finalized."] pub type FlowLeaves < 'a > = Rc < RefCell < Option < Vec < HfPlusLeaf < 'a > > > > > ; pub use crate :: builder :: ClusterIds ; # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Vec < u32 > > for ClusterIds < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , & 'a Vec < u32 > > for ClusterIds < 'a > { } # [derive (Copy , Clone)] pub struct ClusterSelfId < 'a > { pub id : usize , pub _phantom : PhantomData < & 'a mut & 'a u32 > , } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < u32 > for ClusterSelfId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , u32 > for ClusterSelfId < 'a > { } pub use crate :: builder :: FlowBuilder ; # [cfg (stageleft_macro)] impl < 'a > Drop for FlowBuilder < 'a > { fn drop (& mut self) { if ! self . finalized { panic ! ("Dropped FlowBuilder without finalizing, you may have forgotten to call `with_default_optimize`, `optimize_with`, or `finalize`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > QuotedContext for FlowBuilder < 'a > { fn create () -> Self { FlowBuilder :: new () } } # [cfg (stageleft_macro)] impl < 'a > FlowBuilder < 'a > { # [allow (clippy :: new_without_default)] pub fn new () -> FlowBuilder < 'a > { FlowBuilder { ir_leaves : Rc :: new (RefCell :: new (Some (Vec :: new ()))) , nodes : RefCell :: new (vec ! []) , clusters : RefCell :: new (vec ! []) , cycle_ids : RefCell :: new (HashMap :: new ()) , next_node_id : RefCell :: new (0) , finalized : false , _phantom : PhantomData , } } pub fn finalize (mut self) -> built :: BuiltFlow < 'a > { self . finalized = true ; built :: BuiltFlow { ir : self . ir_leaves . borrow_mut () . take () . unwrap () , processes : self . nodes . replace (vec ! []) , clusters : self . clusters . replace (vec ! []) , used : false , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> built :: BuiltFlow < 'a > { self . finalize () . with_default_optimize () } pub fn optimize_with (self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> built :: BuiltFlow < 'a > { self . finalize () . optimize_with (f) } pub fn ir_leaves (& self) -> & FlowLeaves < 'a > { & self . ir_leaves } pub fn process < P > (& self) -> Process < P > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . nodes . borrow_mut () . push (id) ; Process { id , _phantom : PhantomData , } } pub fn cluster < C > (& self) -> Cluster < C > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . clusters . borrow_mut () . push (id) ; Cluster { id , _phantom : PhantomData , } } pub fn runtime_context (& self) -> RuntimeContext < 'a > { RuntimeContext { _phantom : PhantomData , } } pub fn cluster_members < C > (& self , cluster : & Cluster < C > ,) -> impl Quoted < 'a , & 'a Vec < u32 > > + Copy + 'a { ClusterIds { id : cluster . id , _phantom : PhantomData , } } pub fn cluster_self_id < C > (& self , cluster : & Cluster < C >) -> impl Quoted < 'a , u32 > + Copy + 'a { ClusterSelfId { id : cluster . id , _phantom : PhantomData , } } pub fn spin < L : Location > (& self , on : & L) -> Stream < 'a , () , Unbounded , NoTick , L > { Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Spin () , location_kind : on . id () , })) ,) } pub fn spin_batch < L : Location > (& self , on : & L , batch_size : impl Quoted < 'a , usize > + Copy + 'a ,) -> Stream < 'a , () , Bounded , Tick , L > { self . spin (on) . flat_map (q ! (move | _ | 0 .. batch_size)) . map (q ! (| _ | ())) . tick_batch () } pub fn source_stream < T , E : FuturesStream < Item = T > + Unpin , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Unbounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Stream (e . into ()) , location_kind : on . id () , })) ,) } pub fn source_iter < T , E : IntoIterator < Item = T > , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Bounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , })) ,) } pub fn singleton < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Singleton < 'a , T , Bounded , NoTick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Singleton :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,)))) ,) } pub fn singleton_first_tick < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Optional < 'a , T , Bounded , Tick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,) } pub fn source_interval < L : Location > (& self , on : & L , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , () , Unbounded , NoTick , L > { let interval = interval . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : on . id () , })) ,) } pub fn source_interval_delayed < L : Location > (& self , on : & L , delay : impl Quoted < 'a , Duration > + Copy + 'a , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , tokio :: time :: Instant , Unbounded , NoTick , L > { self . source_stream (on , q ! (tokio_stream :: wrappers :: IntervalStream :: new (tokio :: time :: interval_at (tokio :: time :: Instant :: now () + delay , interval))) ,) . tick_batch () . first () . latest () } pub fn cycle < S : CycleCollection < 'a > > (& self , on : & S :: Location) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , on . id ()) ,) } pub fn cycle_with_initial < S : CycleCollectionWithInitial < 'a > > (& self , on : & S :: Location , initial : S ,) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , initial , on . id ()) ,) } } } pub use builder :: FlowBuilder ; pub mod ir { pub use core :: panic ; pub use std :: cell :: RefCell ; pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow_lang :: graph :: FlatGraphBuilder ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: ToTokens ; pub use syn :: parse_quote ; pub use crate :: deploy :: Deploy ; pub use crate :: location :: LocationId ; pub use crate :: ir :: DebugExpr ; # [cfg (stageleft_macro)] impl From < syn :: Expr > for DebugExpr { fn from (expr : syn :: Expr) -> DebugExpr { DebugExpr (expr) } } # [cfg (stageleft_macro)] impl Deref for DebugExpr { type Target = syn :: Expr ; fn deref (& self) -> & Self :: Target { & self . 0 } } # [cfg (stageleft_macro)] impl ToTokens for DebugExpr { fn to_tokens (& self , tokens : & mut TokenStream) { self . 0 . to_tokens (tokens) ; } } # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugExpr { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "{}" , self . 0 . to_token_stream ()) } } pub use crate :: ir :: DebugInstantiate ; # [cfg (stageleft_macro)] impl < 'a > std :: fmt :: Debug for DebugInstantiate < 'a > { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<network instantiate>") } } pub use crate :: ir :: DebugPipelineFn ; # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugPipelineFn { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<function>") } } pub use crate :: ir :: HfPlusSource ; pub use crate :: ir :: HfPlusLeaf ; # [cfg (stageleft_macro)] impl < 'a > HfPlusLeaf < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . compile_network :: < D > (compile_env , s , nodes , clusters) ; } , seen_tees ,) } pub fn connect_network (self , seen_tees : & mut SeenTees < 'a >) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . connect_network (s) ; } , seen_tees ,) } pub fn transform_children (self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) -> HfPlusLeaf < 'a > { match self { HfPlusLeaf :: ForEach { f , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: ForEach { f , input } } HfPlusLeaf :: DestSink { sink , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: DestSink { sink , input } } HfPlusLeaf :: CycleSink { ident , location_kind , mut input , } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: CycleSink { ident , location_kind , input , } } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) { match self { HfPlusLeaf :: ForEach { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> for_each (# f) ; }) ; } HfPlusLeaf :: DestSink { sink , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink) ; }) ; } HfPlusLeaf :: CycleSink { ident , location_kind , input , } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; assert_eq ! (input_location_id , * location_id , "cycle_sink location mismatch") ; graph_builders . entry (* location_id) . or_default () . add_statement (parse_quote ! { # ident = # input_ident ; }) ; } } } } pub use crate :: ir :: HfPlusNode ; pub type SeenTees < 'a > = HashMap < * const RefCell < HfPlusNode < 'a > > , Rc < RefCell < HfPlusNode < 'a > > > > ; # [cfg (stageleft_macro)] impl < 'a > HfPlusNode < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (& mut self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) { self . transform_children (| n , s | n . compile_network :: < D > (compile_env , s , nodes , clusters) , seen_tees ,) ; if let HfPlusNode :: Network { from_location , to_location , instantiate_fn , .. } = self { let (sink_expr , source_expr , connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { let ((sink , source) , connect_fn) = match (from_location , to_location) { (LocationId :: Process (from) , LocationId :: Process (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: o2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Process (from) , LocationId :: Cluster (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: o2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Process (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: m2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Cluster (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: m2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } } ; (sink , source , connect_fn) } DebugInstantiate :: Finalized (_ , _ , _) => panic ! ("network already finalized") , } ; * instantiate_fn = DebugInstantiate :: Finalized (sink_expr , source_expr , connect_fn) ; } } pub fn connect_network (& mut self , seen_tees : & mut SeenTees < 'a >) { self . transform_children (| n , s | n . connect_network (s) , seen_tees) ; if let HfPlusNode :: Network { instantiate_fn , .. } = self { match instantiate_fn { DebugInstantiate :: Building () => panic ! ("network not built") , DebugInstantiate :: Finalized (_ , _ , ref connect_fn) => { connect_fn () ; } } } } pub fn transform_children (& mut self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) { match self { HfPlusNode :: Placeholder => { panic ! () ; } HfPlusNode :: Source { .. } => { } HfPlusNode :: CycleSource { .. } => { } HfPlusNode :: Tee { inner } => { if let Some (transformed) = seen_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { * inner = transformed . clone () ; } else { let transformed_cell = Rc :: new (RefCell :: new (HfPlusNode :: Placeholder)) ; seen_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , transformed_cell . clone () ,) ; let mut orig = inner . replace (HfPlusNode :: Placeholder) ; transform (& mut orig , seen_tees) ; * transformed_cell . borrow_mut () = orig ; * inner = transformed_cell ; } } HfPlusNode :: Persist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Unpersist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Delta (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Union (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossProduct (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossSingleton (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Join (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Difference (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: AntiJoin (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Map { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FlatMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Filter { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FilterMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Sort (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: DeferTick (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Enumerate (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Inspect { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Unique (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Fold { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FoldKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Reduce { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: ReduceKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Network { input , .. } => { transform (input . as_mut () , seen_tees) ; } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) -> (syn :: Ident , usize) { match self { HfPlusNode :: Placeholder => { panic ! () } HfPlusNode :: Persist (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let persist_id = * next_stmt_id ; * next_stmt_id += 1 ; let persist_ident = syn :: Ident :: new (& format ! ("stream_{}" , persist_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # persist_ident = # inner_ident -> persist ::<'static > () ; }) ; (persist_ident , location) } HfPlusNode :: Unpersist (_) => { panic ! ("Unpersist is a marker node and should have been optimized away. This is likely a compiler bug.") } HfPlusNode :: Delta (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let delta_id = * next_stmt_id ; * next_stmt_id += 1 ; let delta_ident = syn :: Ident :: new (& format ! ("stream_{}" , delta_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # delta_ident = # inner_ident -> multiset_delta () ; }) ; (delta_ident , location) } HfPlusNode :: Source { source , location_kind , } => { let source_id = * next_stmt_id ; * next_stmt_id += 1 ; let source_ident = syn :: Ident :: new (& format ! ("stream_{}" , source_id) , Span :: call_site ()) ; let source_stmt = match source { HfPlusSource :: Stream (expr) => { parse_quote ! { # source_ident = source_stream (# expr) ; } } HfPlusSource :: Iter (expr) => { parse_quote ! { # source_ident = source_iter (# expr) ; } } HfPlusSource :: Interval (expr) => { parse_quote ! { # source_ident = source_interval (# expr) ; } } HfPlusSource :: Spin () => { parse_quote ! { # source_ident = spin () ; } } } ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; graph_builders . entry (* location_id) . or_default () . add_statement (source_stmt) ; (source_ident , * location_id) } HfPlusNode :: CycleSource { ident , location_kind , } => { let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; (ident . clone () , * location_id) } HfPlusNode :: Tee { inner } => { if let Some (ret) = built_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { ret . clone () } else { let (inner_ident , inner_location_id) = inner . borrow () . emit (graph_builders , built_tees , next_stmt_id) ; let tee_id = * next_stmt_id ; * next_stmt_id += 1 ; let tee_ident = syn :: Ident :: new (& format ! ("stream_{}" , tee_id) , Span :: call_site ()) ; let builder = graph_builders . entry (inner_location_id) . or_default () ; builder . add_statement (parse_quote ! { # tee_ident = # inner_ident -> tee () ; }) ; built_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , (tee_ident . clone () , inner_location_id) ,) ; (tee_ident , inner_location_id) } } HfPlusNode :: Union (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "union inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let union_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # union_ident = union () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [0] # union_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # union_ident ; }) ; (union_ident , left_location_id) } HfPlusNode :: CrossSingleton (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "cross_singleton inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let cross_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # cross_ident = cross_singleton () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [input] # cross_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [single] # cross_ident ; }) ; (cross_ident , left_location_id) } HfPlusNode :: CrossProduct (..) | HfPlusNode :: Join (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: CrossProduct (..)) { parse_quote ! (cross_join_multiset) } else { parse_quote ! (join_multiset) } ; let (HfPlusNode :: CrossProduct (left , right) | HfPlusNode :: Join (left , right)) = self else { unreachable ! () } ; let (left_inner , left_was_persist) = if let HfPlusNode :: Persist (left) = left . as_ref () { (left , true) } else { (left , false) } ; let (right_inner , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left_inner . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right_inner . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "join / cross product inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; match (left_was_persist , right_was_persist) { (true , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'static > () ; }) ; } (true , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'tick > () ; }) ; } (false , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } (false , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } } ; builder . add_statement (parse_quote ! { # left_ident -> [0] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Difference (..) | HfPlusNode :: AntiJoin (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Difference (..)) { parse_quote ! (difference_multiset) } else { parse_quote ! (anti_join_multiset) } ; let (HfPlusNode :: Difference (left , right) | HfPlusNode :: AntiJoin (left , right)) = self else { unreachable ! () } ; let (right , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "difference / anti join inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; if right_was_persist { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } else { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } builder . add_statement (parse_quote ! { # left_ident -> [pos] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [neg] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Map { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let map_id = * next_stmt_id ; * next_stmt_id += 1 ; let map_ident = syn :: Ident :: new (& format ! ("stream_{}" , map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # map_ident = # input_ident -> map (# f) ; }) ; (map_ident , input_location_id) } HfPlusNode :: FlatMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let flat_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let flat_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , flat_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # flat_map_ident = # input_ident -> flat_map (# f) ; }) ; (flat_map_ident , input_location_id) } HfPlusNode :: Filter { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_ident = # input_ident -> filter (# f) ; }) ; (filter_ident , input_location_id) } HfPlusNode :: FilterMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_map_ident = # input_ident -> filter_map (# f) ; }) ; (filter_map_ident , input_location_id) } HfPlusNode :: Sort (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sort_id = * next_stmt_id ; * next_stmt_id += 1 ; let sort_ident = syn :: Ident :: new (& format ! ("stream_{}" , sort_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # sort_ident = # input_ident -> sort () ; }) ; (sort_ident , input_location_id) } HfPlusNode :: DeferTick (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let defer_tick_id = * next_stmt_id ; * next_stmt_id += 1 ; let defer_tick_ident = syn :: Ident :: new (& format ! ("stream_{}" , defer_tick_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # defer_tick_ident = # input_ident -> defer_tick_lazy () ; }) ; (defer_tick_ident , input_location_id) } HfPlusNode :: Enumerate (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let enumerate_id = * next_stmt_id ; * next_stmt_id += 1 ; let enumerate_ident = syn :: Ident :: new (& format ! ("stream_{}" , enumerate_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # enumerate_ident = # input_ident -> enumerate () ; }) ; (enumerate_ident , input_location_id) } HfPlusNode :: Inspect { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let inspect_id = * next_stmt_id ; * next_stmt_id += 1 ; let inspect_ident = syn :: Ident :: new (& format ! ("stream_{}" , inspect_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # inspect_ident = # input_ident -> inspect (# f) ; }) ; (inspect_ident , input_location_id) } HfPlusNode :: Unique (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let unique_id = * next_stmt_id ; * next_stmt_id += 1 ; let unique_ident = syn :: Ident :: new (& format ! ("stream_{}" , unique_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # unique_ident = # input_ident -> unique ::<'tick > () ; }) ; (unique_ident , input_location_id) } HfPlusNode :: Fold { .. } | HfPlusNode :: FoldKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Fold { .. }) { parse_quote ! (fold) } else { parse_quote ! (fold_keyed) } ; let (HfPlusNode :: Fold { init , acc , input } | HfPlusNode :: FoldKeyed { init , acc , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let fold_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'static > (# init , # acc) ; }) ; } else { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'tick > (# init , # acc) ; }) ; } (fold_ident , input_location_id) } HfPlusNode :: Reduce { .. } | HfPlusNode :: ReduceKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Reduce { .. }) { parse_quote ! (reduce) } else { parse_quote ! (reduce_keyed) } ; let (HfPlusNode :: Reduce { f , input } | HfPlusNode :: ReduceKeyed { f , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let reduce_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'static > (# f) ; }) ; } else { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'tick > (# f) ; }) ; } (reduce_ident , input_location_id) } HfPlusNode :: Network { from_location : _ , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input , } => { let (sink_expr , source_expr , _connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { panic ! ("Expected the network to be finalized") } DebugInstantiate :: Finalized (sink , source , connect_fn) => { (sink , source , connect_fn) } } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sender_builder = graph_builders . entry (input_location_id) . or_default () ; if let Some (serialize_pipeline) = serialize_pipeline { sender_builder . add_statement (parse_quote ! { # input_ident -> # serialize_pipeline -> dest_sink (# sink_expr) ; }) ; } else { sender_builder . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink_expr) ; }) ; } let to_id = match to_location { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let receiver_builder = graph_builders . entry (* to_id) . or_default () ; let receiver_stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let receiver_stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , receiver_stream_id) , Span :: call_site ()) ; if let Some (deserialize_pipeline) = deserialize_pipeline { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) -> # deserialize_pipeline ; }) ; } else { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) ; }) ; } (receiver_stream_ident , * to_id) } } } } } pub mod persist_pullup { pub use std :: cell :: RefCell ; pub use std :: collections :: HashSet ; pub use std :: ops :: Deref ; pub use crate :: ir :: * ; pub fn persist_pullup_node < 'a > (node : & mut HfPlusNode < 'a > , seen_tees : & mut SeenTees < 'a > , persist_pulled_tees : & mut HashSet < * const RefCell < HfPlusNode < 'a > > > ,) { node . transform_children (| n , s | persist_pullup_node (n , s , persist_pulled_tees) , seen_tees ,) ; match node { HfPlusNode :: Unpersist (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Unpersist (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Delta (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Delta (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Tee { inner } => { if persist_pulled_tees . contains (& (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >)) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } else { let inner_borrow = inner . borrow () ; if let HfPlusNode :: Persist (_) = inner_borrow . deref () { drop (inner_borrow) ; persist_pulled_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >) ; if let HfPlusNode :: Persist (box behind_persist) = inner . replace (HfPlusNode :: Placeholder) { * inner . borrow_mut () = behind_persist ; } else { unreachable ! () } * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } } } HfPlusNode :: Map { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Map { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Map { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: FlatMap { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: FlatMap { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: FlatMap { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Filter { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Filter { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Filter { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Network { input : box HfPlusNode :: Persist (_) , .. } => { if let HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Union (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Union (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Union (left , right))) ; } else { unreachable ! () } } HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: CrossProduct (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,) ,)))) ; } else { unreachable ! () } } HfPlusNode :: Join (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Join (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: Join (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,))))) ; } else { unreachable ! () } } _ => { } } } pub fn persist_pullup (ir : Vec < HfPlusLeaf >) -> Vec < HfPlusLeaf > { let mut seen_tees = Default :: default () ; let mut persist_pulled_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| n , s | persist_pullup_node (n , s , & mut persist_pulled_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn persist_pullup_through_map () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } # [test] fn persist_pullup_behind_tee () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; let before_tee = flow . source_iter (& process , q ! (0 .. 10)) . tick_batch () . persist () ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } } } pub mod profiler { pub use std :: cell :: RefCell ; pub use hydroflow :: futures :: channel :: mpsc :: UnboundedSender ; pub use stageleft :: * ; pub use crate as hydroflow_plus ; pub use crate :: ir :: * ; pub use crate :: RuntimeContext ; pub fn increment_counter (count : & mut u64) { * count += 1 ; } pub fn quoted_any_fn < 'a , F : Fn (& usize) + 'a , Q : IntoQuotedMut < 'a , F > > (q : Q) -> Q { q } # [doc = " Add a profiling node before each node to count the cardinality of its input"] pub fn add_profiling_node < 'a > (node : & mut HfPlusNode < 'a > , _context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > , id : & mut u32 , seen_tees : & mut SeenTees < 'a > ,) { let my_id = * id ; * id += 1 ; node . transform_children (| node , seen_tees | { add_profiling_node (node , _context , counters , counter_queue , id , seen_tees) } , seen_tees ,) ; let orig_node = std :: mem :: replace (node , HfPlusNode :: Placeholder) ; * node = HfPlusNode :: Inspect { f : quoted_any_fn (q ! ({ counter_queue . borrow () . unbounded_send ((my_id as usize , counters . borrow () [my_id as usize])) . unwrap () ; counters . borrow_mut () [my_id as usize] = 0 ; move | _ | { hydroflow_plus :: profiler :: increment_counter (& mut counters . borrow_mut () [my_id as usize] ,) ; } })) . splice () . into () , input : Box :: new (orig_node) , } } # [doc = " Count the cardinality of each input and periodically output to a file"] pub fn profiling < 'a > (ir : Vec < HfPlusLeaf < 'a > > , context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > ,) -> Vec < HfPlusLeaf < 'a > > { let mut id = 0 ; let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | { add_profiling_node (node , context , counters , counter_queue , & mut id , seen_tees) } , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn profiler_wrapping_all_operators () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let runtime_context = flow . runtime_context () ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (& built . ir ()) ; let counters = RuntimeData :: new ("Fake") ; let counter_queue = RuntimeData :: new ("Fake") ; let pushed_down = built . with_default_optimize () . optimize_with (| ir | super :: profiling (ir , runtime_context , counters , counter_queue)) ; insta :: assert_debug_snapshot ! (& pushed_down . ir ()) ; let _ = pushed_down . compile_no_network :: < MultiGraph > () ; } } } pub mod properties { pub use std :: collections :: HashSet ; pub use stageleft :: * ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , SeenTees } ; pub use crate :: properties :: PropertyDatabase ; # [doc = " Allows us to convert the hydroflow datatype for folds to a binary operation for the algebra"] # [doc = " property tests."] # [allow (dead_code)] pub fn convert_hf_to_binary < I , A : Default , F : Fn (& mut A , I) > (f : F) -> impl Fn (I , I) -> A { move | a , b | { let mut acc = Default :: default () ; f (& mut acc , a) ; f (& mut acc , b) ; acc } } # [cfg (stageleft_macro)] impl PropertyDatabase { # [doc = " Tags the expression as commutative."] pub fn add_commutative_tag < 'a , I , A , F : Fn (& mut A , I) , Q : Quoted < 'a , F > + Clone > (& mut self , expr : Q ,) -> Q { let expr_clone = expr . clone () ; self . commutative . insert (expr_clone . splice ()) ; expr } pub fn is_tagged_commutative (& self , expr : & syn :: Expr) -> bool { self . commutative . contains (expr) } } pub fn properties_optimize_node < 'a > (node : & mut HfPlusNode < 'a > , db : & PropertyDatabase , seen_tees : & mut SeenTees < 'a > ,) { node . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , seen_tees ,) ; match node { HfPlusNode :: ReduceKeyed { f , .. } if db . is_tagged_commutative (& f . 0) => { dbg ! ("IDENTIFIED COMMUTATIVE OPTIMIZATION for {:?}" , & f) ; } _ => { } } } pub fn properties_optimize < 'a > (ir : Vec < HfPlusLeaf < 'a > > , db : & PropertyDatabase ,) -> Vec < HfPlusLeaf < 'a > > { let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use super :: * ; use crate :: deploy :: SingleProcessGraph ; use crate :: FlowBuilder ; # [test] fn test_property_database () { let mut db = PropertyDatabase :: default () ; assert ! (! db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; let _ = db . add_commutative_tag (q ! (| a : & mut i32 , b : i32 | * a += b)) ; assert ! (db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; } # [test] fn test_property_optimized () { let flow = FlowBuilder :: new () ; let mut database = PropertyDatabase :: default () ; let process = flow . process :: < () > () ; let counter_func = q ! (| count : & mut i32 , _ | * count += 1) ; let _ = database . add_commutative_tag (counter_func) ; flow . source_iter (& process , q ! (vec ! [])) . map (q ! (| string : String | (string , ()))) . tick_batch () . fold_keyed (q ! (|| 0) , counter_func) . all_ticks () . for_each (q ! (| (string , count) | println ! ("{}: {}" , string , count))) ; let built = flow . finalize () . optimize_with (| ir | properties_optimize (ir , & database)) . with_default_optimize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let _ = built . compile_no_network :: < SingleProcessGraph > () ; } } } pub use crate :: RuntimeContext ; # [cfg (stageleft_macro)] impl Copy for RuntimeContext < '_ > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Context > for RuntimeContext < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (quote ! (& context))) } } pub use crate :: HfCompiled ; # [cfg (stageleft_macro)] impl < 'a , ID > HfCompiled < 'a , ID > { pub fn hydroflow_ir (& self) -> & BTreeMap < usize , HydroflowGraph > { & self . hydroflow_ir } } # [cfg (stageleft_macro)] impl < 'a > HfCompiled < 'a , usize > { pub fn with_dynamic_id (self , id : impl Quoted < 'a , usize >) -> HfBuiltWithId < 'a > { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; let mut conditioned_tokens = None ; for (subgraph_id , flat_graph) in self . hydroflow_ir { let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; let my_extra_stmts = self . extra_stmts . get (& subgraph_id) . cloned () . unwrap_or_default () ; if let Some (conditioned_tokens) = conditioned_tokens . as_mut () { * conditioned_tokens = syn :: parse_quote ! { # conditioned_tokens else if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } } ; } else { conditioned_tokens = Some (syn :: parse_quote ! { if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } }) ; } } let conditioned_tokens : TokenStream = conditioned_tokens . unwrap () ; let id = id . splice () ; HfBuiltWithId { tokens : syn :: parse_quote ! ({ let __given_id = # id ; # conditioned_tokens else { panic ! ("Invalid node id: {}" , __given_id) ; } }) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfCompiled < 'a , () > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfCompiled < 'a , () > { fn to_tokens (mut self) -> (Option < TokenStream > , Option < TokenStream >) { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; if self . hydroflow_ir . len () != 1 { panic ! ("Expected exactly one subgraph in the Hydroflow IR") ; } let flat_graph = self . hydroflow_ir . remove (& 0) . unwrap () ; let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; (None , Some (tokens)) } } pub use crate :: HfBuiltWithId ; # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfBuiltWithId < 'a > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfBuiltWithId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (self . tokens)) } }
[INFO] [stdout] 1 + pub use std :: collections :: BTreeMap ; pub use std :: marker :: PhantomData ; pub use hydroflow :: scheduled :: context :: Context ; pub use hydroflow :: scheduled :: graph :: Hydroflow ; pub use hydroflow :: * ; pub use lang :: graph :: { partition_graph , HydroflowGraph } ; pub use proc_macro2 :: TokenStream ; pub use quote :: quote ; pub use stageleft :: runtime_support :: FreeVariable ; pub use stageleft :: Quoted ; pub mod runtime_support { pub use bincode ; } pub mod stream { pub use std :: cell :: RefCell ; pub use std :: hash :: Hash ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow :: bytes :: Bytes ; pub use hydroflow :: futures :: Sink ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: quote ; pub use serde :: de :: DeserializeOwned ; pub use serde :: Serialize ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use syn :: parse_quote ; pub use crate :: builder :: { ClusterIds , FlowLeaves } ; pub use crate :: cycle :: { CycleCollection , CycleComplete } ; pub use crate :: ir :: { DebugInstantiate , HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { CanSend , Location , LocationId } ; pub use crate :: { Cluster , Optional , Singleton } ; pub use crate :: stream :: Unbounded ; pub use crate :: stream :: Bounded ; pub use crate :: stream :: NoTick ; pub use crate :: stream :: Tick ; pub use crate :: stream :: Stream ; # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Stream { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Stream < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Stream { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , C , N > > ,) -> Stream < 'a , (T , O) , W , C , N > where O : Clone , { let other : Optional < 'a , O , Bounded , C , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn cross_product < O > (self , other : Stream < 'a , O , W , C , N >) -> Stream < 'a , (T , O) , W , C , N > where T : Clone , O : Clone , { if self . location_kind != other . location_kind { panic ! ("cross_product must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossProduct (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn union (self , other : Stream < 'a , T , W , C , N >) -> Stream < 'a , T , W , C , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn dest_sink < S : Unpin + Sink < T > + 'a > (self , sink : impl Quoted < 'a , S >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: DestSink { sink : sink . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn first (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } # [doc = " Allow this stream through if the other stream has elements, otherwise the output is empty."] pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } # [doc = " Allow this stream through if the other stream is empty, otherwise the output is empty."] pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn enumerate (self) -> Stream < 'a , (usize , T) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Enumerate (Box :: new (self . ir_node . into_inner ())) ,) } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn sort (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Ord , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Sort (Box :: new (self . ir_node . into_inner ())) ,) } pub fn count (self) -> Singleton < 'a , usize , Bounded , Tick , N > { self . fold (q ! (|| 0usize) , q ! (| count , _ | * count += 1)) } pub fn delta (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } pub fn unique (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Eq + Hash , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unique (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn tick_batch (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_prefix (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { self . tick_batch () . persist () } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn for_each < F : Fn (T) + 'a > (self , f : impl IntoQuotedMut < 'a , F >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: ForEach { input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , f : f . splice () . into () , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Unbounded , NoTick , N > { pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . tick_batch () . continue_if (samples . first ()) . all_ticks () } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Unbounded , NoTick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , C , N : Location > Stream < 'a , T , Bounded , C , N > { pub fn filter_not_in (self , other : Stream < 'a , T , Bounded , C , N >) -> Stream < 'a , T , Bounded , C , N > where T : Eq + Hash , { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Difference (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Stream < 'a , & T , W , C , N > { pub fn cloned (self) -> Stream < 'a , T , W , C , N > { self . map (q ! (| d | d . clone ())) } } # [cfg (stageleft_macro)] impl < 'a , K , V1 , W , C , N : Location > Stream < 'a , (K , V1) , W , C , N > { pub fn join < W2 , V2 > (self , n : Stream < 'a , (K , V2) , W2 , C , N > ,) -> Stream < 'a , (K , (V1 , V2)) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Join (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } pub fn anti_join < W2 > (self , n : Stream < 'a , K , W2 , C , N >) -> Stream < 'a , (K , V1) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("anti_join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: AntiJoin (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , K : Eq + Hash , V , N : Location > Stream < 'a , (K , V) , Bounded , Tick , N > { pub fn fold_keyed < A , I : Fn () -> A + 'a , F : Fn (& mut A , V) + 'a > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , A) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FoldKeyed { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce_keyed < F : Fn (& mut V , V) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , V) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: ReduceKeyed { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } pub fn get_this_crate () -> TokenStream { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , Span :: call_site ()) ; quote ! { # ident } } } } pub fn serialize_bincode < T : Serialize > (is_demux : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if is_demux { parse_quote ! { map (| (id , data) | { (id , # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into ()) }) } } else { parse_quote ! { map (| data | { # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into () }) } } } pub fn deserialize_bincode < T : DeserializeOwned > (tagged : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if tagged { parse_quote ! { map (| res | { let (id , b) = res . unwrap () ; (id , # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& b) . unwrap ()) }) } } else { parse_quote ! { map (| res | { # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& res . unwrap ()) . unwrap () }) } } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn send_bincode < N2 : Location , CoreType > (self , other : & N2 ,) -> Stream < 'a , N :: Out < CoreType > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T > , CoreType : Serialize + DeserializeOwned , { let serialize_pipeline = Some (serialize_bincode :: < CoreType > (N :: is_demux ())) ; let deserialize_pipeline = Some (deserialize_bincode :: < CoreType > (N :: is_tagged ())) ; Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bytes < N2 : Location > (self , other : & N2 ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T > , { Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline : None , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline : if N :: is_tagged () { Some (parse_quote ! (map (| (id , b) | (id , b . unwrap () . freeze ())))) } else { Some (parse_quote ! (map (| b | b . unwrap () . freeze ()))) } , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bincode_interleaved < N2 : Location , Tag , CoreType > (self , other : & N2 ,) -> Stream < 'a , CoreType , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T , Out < CoreType > = (Tag , CoreType) > , CoreType : Serialize + DeserializeOwned , { self . send_bincode :: < N2 , CoreType > (other) . map (q ! (| (_ , b) | b)) } pub fn send_bytes_interleaved < N2 : Location , Tag > (self , other : & N2 ,) -> Stream < 'a , Bytes , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T , Out < Bytes > = (Tag , Bytes) > , { self . send_bytes :: < N2 > (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bincode < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < T > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) > , T : Clone + Serialize + DeserializeOwned , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bincode (other) } pub fn broadcast_bincode_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , T , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) , Out < T > = (Tag , T) > + 'a , T : Clone + Serialize + DeserializeOwned , { self . broadcast_bincode (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bytes < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) > + 'a , T : Clone , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bytes (other) } pub fn broadcast_bytes_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , Bytes , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) , Out < Bytes > = (Tag , Bytes) > + 'a , T : Clone , { self . broadcast_bytes (other) . map (q ! (| (_ , b) | b)) } } } pub use stream :: { Bounded , NoTick , Stream , Tick , Unbounded } ; pub mod singleton { pub use std :: cell :: RefCell ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use crate :: builder :: FlowLeaves ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial , CycleComplete } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: Stream ; pub use crate :: singleton :: CrossResult ; # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Singleton < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Singleton :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } pub use crate :: singleton :: Singleton ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Singleton { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleComplete < 'a > for Singleton < 'a , T , Bounded , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleCollectionWithInitial < 'a > for Singleton < 'a , T , Bounded , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , initial : Self , l : LocationId ,) -> Self { Singleton :: new (l , ir_leaves , HfPlusNode :: Union (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , }) , initial . ir_node . into_inner () . into () ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Singleton < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Singleton { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , U , W , C , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (Self :: other_ir_node (other)) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Singleton < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CrossSingleton (Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , Box :: new (HfPlusNode :: Unpersist (Box :: new (Self :: other_ir_node (other)))) ,))) ,) } } pub use crate :: singleton :: Optional ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Optional { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } pub fn some (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: new (singleton . location_kind , singleton . ir_leaves , singleton . ir_node . into_inner () ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > From < Singleton < 'a , T , W , C , N > > for Optional < 'a , T , W , C , N > { fn from (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: some (singleton) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Optional < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Optional { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn into_stream (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , Tick , N > > ,) -> Optional < 'a , (T , O) , Bounded , Tick , N > where O : Clone , { let other : Optional < 'a , O , Bounded , Tick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn union (self , other : Optional < 'a , T , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Optional < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_samples (self) -> Stream < 'a , T , Unbounded , NoTick , N > { self . latest_tick () . all_ticks () } pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . latest_tick () . continue_if (samples . first ()) . latest () . tick_samples () } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Unbounded , NoTick , N > > ,) -> Optional < 'a , (T , O) , Unbounded , NoTick , N > where O : Clone , { let other : Optional < 'a , O , Unbounded , NoTick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } self . latest_tick () . cross_singleton (other . latest_tick ()) . latest () } } } pub use singleton :: { Optional , Singleton } ; pub mod location { pub use std :: marker :: PhantomData ; pub use crate :: location :: LocationId ; pub use crate :: location :: Location ; pub use crate :: location :: Process ; # [cfg (stageleft_macro)] impl < P > Clone for Process < P > { fn clone (& self) -> Self { Process { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < P > Location for Process < P > { fn id (& self) -> LocationId { LocationId :: Process (self . id) } } pub use crate :: location :: Cluster ; # [cfg (stageleft_macro)] impl < C > Clone for Cluster < C > { fn clone (& self) -> Self { Cluster { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < C > Location for Cluster < C > { fn id (& self) -> LocationId { LocationId :: Cluster (self . id) } } pub use crate :: location :: CanSend ; # [cfg (stageleft_macro)] impl < P1 , P2 > CanSend < Process < P2 > > for Process < P1 > { type In < T > = T ; type Out < T > = T ; fn is_demux () -> bool { false } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < P1 , C2 > CanSend < Cluster < C2 > > for Process < P1 > { type In < T > = (u32 , T) ; type Out < T > = T ; fn is_demux () -> bool { true } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < C1 , P2 > CanSend < Process < P2 > > for Cluster < C1 > { type In < T > = T ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { false } fn is_tagged () -> bool { true } } # [cfg (stageleft_macro)] impl < C1 , C2 > CanSend < Cluster < C2 > > for Cluster < C1 > { type In < T > = (u32 , T) ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { true } fn is_tagged () -> bool { true } } } pub use location :: { Cluster , Process } ; pub mod deploy { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use stageleft :: Quoted ; pub mod graphs { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use super :: { LocalDeploy , Node , ProcessSpec } ; pub use crate :: deploy :: graphs :: SingleProcessGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for SingleProcessGraph { type Process = SingleNode ; type Cluster = SingleNode ; type Meta = () ; type GraphId = () ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { SingleNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { SingleNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , SingleProcessGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> SingleNode { SingleNode { } } } pub use crate :: deploy :: graphs :: SingleNode ; # [cfg (stageleft_macro)] impl Node for SingleNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } pub use crate :: deploy :: graphs :: MultiGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for MultiGraph { type Process = MultiNode ; type Cluster = MultiNode ; type Meta = () ; type GraphId = usize ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { MultiNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { MultiNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , MultiGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> MultiNode { MultiNode { } } } pub use crate :: deploy :: graphs :: MultiNode ; # [cfg (stageleft_macro)] impl Node for MultiNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } } pub use graphs :: * ; pub use crate :: deploy :: LocalDeploy ; pub use crate :: deploy :: Deploy ; # [cfg (stageleft_macro)] impl < 'a , T : Deploy < 'a , Process = N , Cluster = C , Meta = M , GraphId = R > , N : Node < Meta = M > , C : Node < Meta = M > , M : Default , R , > LocalDeploy < 'a > for T { type Process = N ; type Cluster = C ; type Meta = M ; type GraphId = R ; fn has_trivial_node () -> bool { < T as Deploy < 'a > > :: has_trivial_node () } fn trivial_process (id : usize) -> Self :: Process { < T as Deploy < 'a > > :: trivial_process (id) } fn trivial_cluster (id : usize) -> Self :: Cluster { < T as Deploy < 'a > > :: trivail_cluster (id) } } pub use crate :: deploy :: ProcessSpec ; pub use crate :: deploy :: ClusterSpec ; pub use crate :: deploy :: Node ; } pub use deploy :: { ClusterSpec , Deploy , ProcessSpec } ; pub mod cycle { pub use std :: marker :: PhantomData ; pub use crate :: builder :: FlowLeaves ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: cycle :: CycleComplete ; pub use crate :: cycle :: CycleCollection ; pub use crate :: cycle :: CycleCollectionWithInitial ; pub use crate :: cycle :: HfCycle ; # [cfg (stageleft_macro)] impl < 'a , S : CycleComplete < 'a > > HfCycle < 'a , S > { pub fn complete (self , stream : S) { let ident = self . ident ; S :: complete (stream , ident) } } } pub use cycle :: HfCycle ; pub mod builder { pub use std :: cell :: RefCell ; pub use std :: collections :: HashMap ; pub use std :: marker :: PhantomData ; pub use std :: rc :: Rc ; pub use std :: time :: Duration ; pub use hydroflow :: futures :: stream :: Stream as FuturesStream ; pub use hydroflow :: { tokio , tokio_stream } ; pub use internal :: TokenStream ; pub use proc_macro2 :: Span ; pub use quote :: quote ; pub use runtime_support :: FreeVariable ; pub use stageleft :: * ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Cluster , Location , LocationId , Process } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: { HfCycle , Optional , RuntimeContext , Singleton , Stream } ; pub mod built { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use hydroflow_lang :: graph :: { eliminate_extra_unions_tees , HydroflowGraph } ; pub use super :: deploy :: { DeployFlow , DeployResult } ; pub use crate :: deploy :: { ClusterSpec , Deploy , LocalDeploy , ProcessSpec } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Cluster , Process } ; pub use crate :: HfCompiled ; pub use crate :: builder :: built :: BuiltFlow ; # [cfg (stageleft_macro)] impl < 'a > Drop for BuiltFlow < 'a > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped BuiltFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn ir (& self) -> & Vec < HfPlusLeaf < 'a > > { & self . ir } pub fn optimize_with (mut self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> BuiltFlow < 'a > { self . used = true ; BuiltFlow { ir : f (std :: mem :: take (& mut self . ir)) , processes : std :: mem :: take (& mut self . processes) , clusters : std :: mem :: take (& mut self . clusters) , used : false , _phantom : PhantomData , } } } pub fn build_inner (ir : & mut Vec < HfPlusLeaf >) -> BTreeMap < usize , HydroflowGraph > { let mut builders = BTreeMap :: new () ; let mut built_tees = HashMap :: new () ; let mut next_stmt_id = 0 ; for leaf in ir { leaf . emit (& mut builders , & mut built_tees , & mut next_stmt_id) ; } builders . into_iter () . map (| (k , v) | { let (mut flat_graph , _ , _) = v . build () ; eliminate_extra_unions_tees (& mut flat_graph) ; (k , flat_graph) }) . collect () } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn compile_no_network < D : LocalDeploy < 'a > > (mut self) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; HfCompiled { hydroflow_ir : build_inner (& mut self . ir) , extra_stmts : BTreeMap :: new () , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> BuiltFlow < 'a > { self . optimize_with (crate :: persist_pullup :: persist_pullup) } fn into_deploy < D : LocalDeploy < 'a > > (mut self) -> DeployFlow < 'a , D > { self . used = true ; let processes = if D :: has_trivial_node () { self . processes . iter () . map (| id | (* id , D :: trivial_process (* id))) . collect () } else { HashMap :: new () } ; let clusters = if D :: has_trivial_node () { self . clusters . iter () . map (| id | (* id , D :: trivial_cluster (* id))) . collect () } else { HashMap :: new () } ; DeployFlow { ir : std :: mem :: take (& mut self . ir) , nodes : processes , clusters , used : false , _phantom : PhantomData , } } pub fn with_process < P , D : LocalDeploy < 'a > > (self , process : & Process < P > , spec : impl ProcessSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_process (process , spec) } pub fn with_cluster < C , D : LocalDeploy < 'a > > (self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_cluster (cluster , spec) } pub fn compile < D : Deploy < 'a > + 'a > (self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . into_deploy :: < D > () . compile (env) } pub fn deploy < D : Deploy < 'a , CompileEnv = () > + 'a > (self , env : & mut D :: InstantiateEnv ,) -> DeployResult < 'a , D > { self . into_deploy :: < D > () . deploy (env) } } } pub mod deploy { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use proc_macro2 :: Span ; pub use stageleft :: Quoted ; pub use super :: built :: build_inner ; pub use crate :: deploy :: { LocalDeploy , Node } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: { Cluster , ClusterSpec , Deploy , HfCompiled , Process , ProcessSpec } ; pub use crate :: builder :: deploy :: DeployFlow ; # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > Drop for DeployFlow < 'a , D > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped DeployFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > DeployFlow < 'a , D > { pub fn with_process < P > (mut self , process : & Process < P > , spec : impl ProcessSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < P > () . to_string () ; self . nodes . insert (process . id , spec . build (process . id , & tag_name)) ; self } pub fn with_cluster < C > (mut self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < C > () . to_string () ; self . clusters . insert (cluster . id , spec . build (cluster . id , & tag_name)) ; self } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployFlow < 'a , D > { pub fn compile (mut self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; let mut seen_tees : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | leaf . compile_network :: < D > (env , & mut seen_tees , & self . nodes , & self . clusters)) . collect () ; let extra_stmts = self . extra_stmts (env) ; HfCompiled { hydroflow_ir : build_inner (& mut ir_leaves_networked) , extra_stmts , _phantom : PhantomData , } } fn extra_stmts (& self , env : & < D as Deploy < 'a > > :: CompileEnv) -> BTreeMap < usize , Vec < syn :: Stmt > > { let all_locations_count = self . nodes . len () + self . clusters . len () ; let mut extra_stmts : BTreeMap < usize , Vec < syn :: Stmt > > = BTreeMap :: new () ; for & c_id in self . clusters . keys () { let self_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , c_id) , Span :: call_site () ,) ; let self_id_expr = D :: cluster_self_id (env) . splice () ; extra_stmts . entry (c_id) . or_default () . push (syn :: parse_quote ! { let # self_id_ident = # self_id_expr ; }) ; for other_location in 0 .. all_locations_count { let other_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , c_id) , Span :: call_site () ,) ; let other_id_expr = D :: cluster_ids (env , c_id) . splice () ; extra_stmts . entry (other_location) . or_default () . push (syn :: parse_quote ! { let # other_id_ident = # other_id_expr ; }) ; } } extra_stmts } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a , CompileEnv = () > > DeployFlow < 'a , D > { # [must_use] pub fn deploy (mut self , env : & mut D :: InstantiateEnv) -> DeployResult < 'a , D > { self . used = true ; let mut seen_tees_instantiate : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | { leaf . compile_network :: < D > (& () , & mut seen_tees_instantiate , & self . nodes , & self . clusters ,) }) . collect () ; let mut compiled = build_inner (& mut ir_leaves_networked) ; let mut extra_stmts = self . extra_stmts (& ()) ; let mut meta = D :: Meta :: default () ; let (mut processes , mut clusters) = (std :: mem :: take (& mut self . nodes) . into_iter () . map (| (node_id , node) | { node . instantiate (env , & mut meta , compiled . remove (& node_id) . unwrap () , extra_stmts . remove (& node_id) . unwrap_or_default () ,) ; (node_id , node) }) . collect :: < HashMap < _ , _ > > () , std :: mem :: take (& mut self . clusters) . into_iter () . map (| (cluster_id , cluster) | { cluster . instantiate (env , & mut meta , compiled . remove (& cluster_id) . unwrap () , extra_stmts . remove (& cluster_id) . unwrap_or_default () ,) ; (cluster_id , cluster) }) . collect :: < HashMap < _ , _ > > () ,) ; for node in processes . values_mut () { node . update_meta (& meta) ; } for cluster in clusters . values_mut () { cluster . update_meta (& meta) ; } let mut seen_tees_connect = HashMap :: new () ; for leaf in ir_leaves_networked { leaf . connect_network (& mut seen_tees_connect) ; } DeployResult { processes , clusters , } } } pub use crate :: builder :: deploy :: DeployResult ; # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployResult < 'a , D > { pub fn get_process < P > (& self , p : & Process < P >) -> & D :: Process { let id = match p . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . processes . get (& id) . unwrap () } pub fn get_cluster < C > (& self , c : & Cluster < C >) -> & D :: Cluster { let id = match c . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . clusters . get (& id) . unwrap () } } } # [doc = " Tracks the leaves of the dataflow IR. This is referenced by"] # [doc = " `Stream` and `HfCycle` to build the IR. The inner option will"] # [doc = " be set to `None` when this builder is finalized."] pub type FlowLeaves < 'a > = Rc < RefCell < Option < Vec < HfPlusLeaf < 'a > > > > > ; pub use crate :: builder :: ClusterIds ; # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Vec < u32 > > for ClusterIds < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , & 'a Vec < u32 > > for ClusterIds < 'a > { } # [derive (Copy , Clone)] pub struct ClusterSelfId < 'a > { pub id : usize , pub _phantom : PhantomData < & 'a mut & 'a u32 > , } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < u32 > for ClusterSelfId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , u32 > for ClusterSelfId < 'a > { } pub use crate :: builder :: FlowBuilder ; # [cfg (stageleft_macro)] impl < 'a > Drop for FlowBuilder < 'a > { fn drop (& mut self) { if ! self . finalized { panic ! ("Dropped FlowBuilder without finalizing, you may have forgotten to call `with_default_optimize`, `optimize_with`, or `finalize`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > QuotedContext for FlowBuilder < 'a > { fn create () -> Self { FlowBuilder :: new () } } # [cfg (stageleft_macro)] impl < 'a > FlowBuilder < 'a > { # [allow (clippy :: new_without_default)] pub fn new () -> FlowBuilder < 'a > { FlowBuilder { ir_leaves : Rc :: new (RefCell :: new (Some (Vec :: new ()))) , nodes : RefCell :: new (vec ! []) , clusters : RefCell :: new (vec ! []) , cycle_ids : RefCell :: new (HashMap :: new ()) , next_node_id : RefCell :: new (0) , finalized : false , _phantom : PhantomData , } } pub fn finalize (mut self) -> built :: BuiltFlow < 'a > { self . finalized = true ; built :: BuiltFlow { ir : self . ir_leaves . borrow_mut () . take () . unwrap () , processes : self . nodes . replace (vec ! []) , clusters : self . clusters . replace (vec ! []) , used : false , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> built :: BuiltFlow < 'a > { self . finalize () . with_default_optimize () } pub fn optimize_with (self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> built :: BuiltFlow < 'a > { self . finalize () . optimize_with (f) } pub fn ir_leaves (& self) -> & FlowLeaves < 'a > { & self . ir_leaves } pub fn process < P > (& self) -> Process < P > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . nodes . borrow_mut () . push (id) ; Process { id , _phantom : PhantomData , } } pub fn cluster < C > (& self) -> Cluster < C > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . clusters . borrow_mut () . push (id) ; Cluster { id , _phantom : PhantomData , } } pub fn runtime_context (& self) -> RuntimeContext < 'a > { RuntimeContext { _phantom : PhantomData , } } pub fn cluster_members < C > (& self , cluster : & Cluster < C > ,) -> impl Quoted < 'a , & 'a Vec < u32 > > + Copy + 'a { ClusterIds { id : cluster . id , _phantom : PhantomData , } } pub fn cluster_self_id < C > (& self , cluster : & Cluster < C >) -> impl Quoted < 'a , u32 > + Copy + 'a { ClusterSelfId { id : cluster . id , _phantom : PhantomData , } } pub fn spin < L : Location > (& self , on : & L) -> Stream < 'a , () , Unbounded , NoTick , L > { Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Spin () , location_kind : on . id () , })) ,) } pub fn spin_batch < L : Location > (& self , on : & L , batch_size : impl Quoted < 'a , usize > + Copy + 'a ,) -> Stream < 'a , () , Bounded , Tick , L > { self . spin (on) . flat_map (q ! (move | _ | 0 .. batch_size)) . map (q ! (| _ | ())) . tick_batch () } pub fn source_stream < T , E : FuturesStream < Item = T > + Unpin , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Unbounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Stream (e . into ()) , location_kind : on . id () , })) ,) } pub fn source_iter < T , E : IntoIterator < Item = T > , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Bounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , })) ,) } pub fn singleton < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Singleton < 'a , T , Bounded , NoTick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Singleton :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,)))) ,) } pub fn singleton_first_tick < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Optional < 'a , T , Bounded , Tick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,) } pub fn source_interval < L : Location > (& self , on : & L , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , () , Unbounded , NoTick , L > { let interval = interval . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : on . id () , })) ,) } pub fn source_interval_delayed < L : Location > (& self , on : & L , delay : impl Quoted < 'a , Duration > + Copy + 'a , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , tokio :: time :: Instant , Unbounded , NoTick , L > { self . source_stream (on , q ! (tokio_stream :: wrappers :: IntervalStream :: new (tokio :: time :: interval_at (tokio :: time :: Instant :: now () + delay , interval))) ,) . tick_batch () . first () . latest () } pub fn cycle < S : CycleCollection < 'a > > (& self , on : & S :: Location) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , on . id ()) ,) } pub fn cycle_with_initial < S : CycleCollectionWithInitial < 'a > > (& self , on : & S :: Location , initial : S ,) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , initial , on . id ()) ,) } } } pub use builder :: FlowBuilder ; pub mod ir { pub use core :: panic ; pub use std :: cell :: RefCell ; pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow_lang :: graph :: FlatGraphBuilder ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: ToTokens ; pub use syn :: parse_quote ; pub use crate :: deploy :: Deploy ; pub use crate :: location :: LocationId ; pub use crate :: ir :: DebugExpr ; # [cfg (stageleft_macro)] impl From < syn :: Expr > for DebugExpr { fn from (expr : syn :: Expr) -> DebugExpr { DebugExpr (expr) } } # [cfg (stageleft_macro)] impl Deref for DebugExpr { type Target = syn :: Expr ; fn deref (& self) -> & Self :: Target { & self . 0 } } # [cfg (stageleft_macro)] impl ToTokens for DebugExpr { fn to_tokens (& self , tokens : & mut TokenStream) { self . 0 . to_tokens (tokens) ; } } # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugExpr { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "{}" , self . 0 . to_token_stream ()) } } pub use crate :: ir :: DebugInstantiate ; # [cfg (stageleft_macro)] impl < 'a > std :: fmt :: Debug for DebugInstantiate < 'a > { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<network instantiate>") } } pub use crate :: ir :: DebugPipelineFn ; # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugPipelineFn { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<function>") } } pub use crate :: ir :: HfPlusSource ; pub use crate :: ir :: HfPlusLeaf ; # [cfg (stageleft_macro)] impl < 'a > HfPlusLeaf < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . compile_network :: < D > (compile_env , s , nodes , clusters) ; } , seen_tees ,) } pub fn connect_network (self , seen_tees : & mut SeenTees < 'a >) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . connect_network (s) ; } , seen_tees ,) } pub fn transform_children (self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) -> HfPlusLeaf < 'a > { match self { HfPlusLeaf :: ForEach { f , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: ForEach { f , input } } HfPlusLeaf :: DestSink { sink , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: DestSink { sink , input } } HfPlusLeaf :: CycleSink { ident , location_kind , mut input , } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: CycleSink { ident , location_kind , input , } } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) { match self { HfPlusLeaf :: ForEach { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> for_each (# f) ; }) ; } HfPlusLeaf :: DestSink { sink , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink) ; }) ; } HfPlusLeaf :: CycleSink { ident , location_kind , input , } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; assert_eq ! (input_location_id , * location_id , "cycle_sink location mismatch") ; graph_builders . entry (* location_id) . or_default () . add_statement (parse_quote ! { # ident = # input_ident ; }) ; } } } } pub use crate :: ir :: HfPlusNode ; pub type SeenTees < 'a > = HashMap < * const RefCell < HfPlusNode < 'a > > , Rc < RefCell < HfPlusNode < 'a > > > > ; # [cfg (stageleft_macro)] impl < 'a > HfPlusNode < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (& mut self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) { self . transform_children (| n , s | n . compile_network :: < D > (compile_env , s , nodes , clusters) , seen_tees ,) ; if let HfPlusNode :: Network { from_location , to_location , instantiate_fn , .. } = self { let (sink_expr , source_expr , connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { let ((sink , source) , connect_fn) = match (from_location , to_location) { (LocationId :: Process (from) , LocationId :: Process (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: o2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Process (from) , LocationId :: Cluster (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: o2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Process (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: m2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Cluster (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: m2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } } ; (sink , source , connect_fn) } DebugInstantiate :: Finalized (_ , _ , _) => panic ! ("network already finalized") , } ; * instantiate_fn = DebugInstantiate :: Finalized (sink_expr , source_expr , connect_fn) ; } } pub fn connect_network (& mut self , seen_tees : & mut SeenTees < 'a >) { self . transform_children (| n , s | n . connect_network (s) , seen_tees) ; if let HfPlusNode :: Network { instantiate_fn , .. } = self { match instantiate_fn { DebugInstantiate :: Building () => panic ! ("network not built") , DebugInstantiate :: Finalized (_ , _ , ref connect_fn) => { connect_fn () ; } } } } pub fn transform_children (& mut self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) { match self { HfPlusNode :: Placeholder => { panic ! () ; } HfPlusNode :: Source { .. } => { } HfPlusNode :: CycleSource { .. } => { } HfPlusNode :: Tee { inner } => { if let Some (transformed) = seen_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { * inner = transformed . clone () ; } else { let transformed_cell = Rc :: new (RefCell :: new (HfPlusNode :: Placeholder)) ; seen_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , transformed_cell . clone () ,) ; let mut orig = inner . replace (HfPlusNode :: Placeholder) ; transform (& mut orig , seen_tees) ; * transformed_cell . borrow_mut () = orig ; * inner = transformed_cell ; } } HfPlusNode :: Persist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Unpersist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Delta (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Union (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossProduct (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossSingleton (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Join (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Difference (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: AntiJoin (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Map { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FlatMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Filter { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FilterMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Sort (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: DeferTick (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Enumerate (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Inspect { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Unique (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Fold { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FoldKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Reduce { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: ReduceKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Network { input , .. } => { transform (input . as_mut () , seen_tees) ; } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) -> (syn :: Ident , usize) { match self { HfPlusNode :: Placeholder => { panic ! () } HfPlusNode :: Persist (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let persist_id = * next_stmt_id ; * next_stmt_id += 1 ; let persist_ident = syn :: Ident :: new (& format ! ("stream_{}" , persist_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # persist_ident = # inner_ident -> persist ::<'static > () ; }) ; (persist_ident , location) } HfPlusNode :: Unpersist (_) => { panic ! ("Unpersist is a marker node and should have been optimized away. This is likely a compiler bug.") } HfPlusNode :: Delta (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let delta_id = * next_stmt_id ; * next_stmt_id += 1 ; let delta_ident = syn :: Ident :: new (& format ! ("stream_{}" , delta_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # delta_ident = # inner_ident -> multiset_delta () ; }) ; (delta_ident , location) } HfPlusNode :: Source { source , location_kind , } => { let source_id = * next_stmt_id ; * next_stmt_id += 1 ; let source_ident = syn :: Ident :: new (& format ! ("stream_{}" , source_id) , Span :: call_site ()) ; let source_stmt = match source { HfPlusSource :: Stream (expr) => { parse_quote ! { # source_ident = source_stream (# expr) ; } } HfPlusSource :: Iter (expr) => { parse_quote ! { # source_ident = source_iter (# expr) ; } } HfPlusSource :: Interval (expr) => { parse_quote ! { # source_ident = source_interval (# expr) ; } } HfPlusSource :: Spin () => { parse_quote ! { # source_ident = spin () ; } } } ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; graph_builders . entry (* location_id) . or_default () . add_statement (source_stmt) ; (source_ident , * location_id) } HfPlusNode :: CycleSource { ident , location_kind , } => { let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; (ident . clone () , * location_id) } HfPlusNode :: Tee { inner } => { if let Some (ret) = built_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { ret . clone () } else { let (inner_ident , inner_location_id) = inner . borrow () . emit (graph_builders , built_tees , next_stmt_id) ; let tee_id = * next_stmt_id ; * next_stmt_id += 1 ; let tee_ident = syn :: Ident :: new (& format ! ("stream_{}" , tee_id) , Span :: call_site ()) ; let builder = graph_builders . entry (inner_location_id) . or_default () ; builder . add_statement (parse_quote ! { # tee_ident = # inner_ident -> tee () ; }) ; built_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , (tee_ident . clone () , inner_location_id) ,) ; (tee_ident , inner_location_id) } } HfPlusNode :: Union (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "union inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let union_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # union_ident = union () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [0] # union_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # union_ident ; }) ; (union_ident , left_location_id) } HfPlusNode :: CrossSingleton (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "cross_singleton inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let cross_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # cross_ident = cross_singleton () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [input] # cross_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [single] # cross_ident ; }) ; (cross_ident , left_location_id) } HfPlusNode :: CrossProduct (..) | HfPlusNode :: Join (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: CrossProduct (..)) { parse_quote ! (cross_join_multiset) } else { parse_quote ! (join_multiset) } ; let (HfPlusNode :: CrossProduct (left , right) | HfPlusNode :: Join (left , right)) = self else { unreachable ! () } ; let (left_inner , left_was_persist) = if let HfPlusNode :: Persist (left) = left . as_ref () { (left , true) } else { (left , false) } ; let (right_inner , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left_inner . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right_inner . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "join / cross product inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; match (left_was_persist , right_was_persist) { (true , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'static > () ; }) ; } (true , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'tick > () ; }) ; } (false , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } (false , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } } ; builder . add_statement (parse_quote ! { # left_ident -> [0] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Difference (..) | HfPlusNode :: AntiJoin (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Difference (..)) { parse_quote ! (difference_multiset) } else { parse_quote ! (anti_join_multiset) } ; let (HfPlusNode :: Difference (left , right) | HfPlusNode :: AntiJoin (left , right)) = self else { unreachable ! () } ; let (right , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "difference / anti join inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; if right_was_persist { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } else { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } builder . add_statement (parse_quote ! { # left_ident -> [pos] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [neg] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Map { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let map_id = * next_stmt_id ; * next_stmt_id += 1 ; let map_ident = syn :: Ident :: new (& format ! ("stream_{}" , map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # map_ident = # input_ident -> map (# f) ; }) ; (map_ident , input_location_id) } HfPlusNode :: FlatMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let flat_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let flat_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , flat_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # flat_map_ident = # input_ident -> flat_map (# f) ; }) ; (flat_map_ident , input_location_id) } HfPlusNode :: Filter { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_ident = # input_ident -> filter (# f) ; }) ; (filter_ident , input_location_id) } HfPlusNode :: FilterMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_map_ident = # input_ident -> filter_map (# f) ; }) ; (filter_map_ident , input_location_id) } HfPlusNode :: Sort (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sort_id = * next_stmt_id ; * next_stmt_id += 1 ; let sort_ident = syn :: Ident :: new (& format ! ("stream_{}" , sort_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # sort_ident = # input_ident -> sort () ; }) ; (sort_ident , input_location_id) } HfPlusNode :: DeferTick (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let defer_tick_id = * next_stmt_id ; * next_stmt_id += 1 ; let defer_tick_ident = syn :: Ident :: new (& format ! ("stream_{}" , defer_tick_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # defer_tick_ident = # input_ident -> defer_tick_lazy () ; }) ; (defer_tick_ident , input_location_id) } HfPlusNode :: Enumerate (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let enumerate_id = * next_stmt_id ; * next_stmt_id += 1 ; let enumerate_ident = syn :: Ident :: new (& format ! ("stream_{}" , enumerate_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # enumerate_ident = # input_ident -> enumerate () ; }) ; (enumerate_ident , input_location_id) } HfPlusNode :: Inspect { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let inspect_id = * next_stmt_id ; * next_stmt_id += 1 ; let inspect_ident = syn :: Ident :: new (& format ! ("stream_{}" , inspect_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # inspect_ident = # input_ident -> inspect (# f) ; }) ; (inspect_ident , input_location_id) } HfPlusNode :: Unique (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let unique_id = * next_stmt_id ; * next_stmt_id += 1 ; let unique_ident = syn :: Ident :: new (& format ! ("stream_{}" , unique_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # unique_ident = # input_ident -> unique ::<'tick > () ; }) ; (unique_ident , input_location_id) } HfPlusNode :: Fold { .. } | HfPlusNode :: FoldKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Fold { .. }) { parse_quote ! (fold) } else { parse_quote ! (fold_keyed) } ; let (HfPlusNode :: Fold { init , acc , input } | HfPlusNode :: FoldKeyed { init , acc , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let fold_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'static > (# init , # acc) ; }) ; } else { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'tick > (# init , # acc) ; }) ; } (fold_ident , input_location_id) } HfPlusNode :: Reduce { .. } | HfPlusNode :: ReduceKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Reduce { .. }) { parse_quote ! (reduce) } else { parse_quote ! (reduce_keyed) } ; let (HfPlusNode :: Reduce { f , input } | HfPlusNode :: ReduceKeyed { f , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let reduce_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'static > (# f) ; }) ; } else { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'tick > (# f) ; }) ; } (reduce_ident , input_location_id) } HfPlusNode :: Network { from_location : _ , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input , } => { let (sink_expr , source_expr , _connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { panic ! ("Expected the network to be finalized") } DebugInstantiate :: Finalized (sink , source , connect_fn) => { (sink , source , connect_fn) } } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sender_builder = graph_builders . entry (input_location_id) . or_default () ; if let Some (serialize_pipeline) = serialize_pipeline { sender_builder . add_statement (parse_quote ! { # input_ident -> # serialize_pipeline -> dest_sink (# sink_expr) ; }) ; } else { sender_builder . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink_expr) ; }) ; } let to_id = match to_location { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let receiver_builder = graph_builders . entry (* to_id) . or_default () ; let receiver_stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let receiver_stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , receiver_stream_id) , Span :: call_site ()) ; if let Some (deserialize_pipeline) = deserialize_pipeline { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) -> # deserialize_pipeline ; }) ; } else { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) ; }) ; } (receiver_stream_ident , * to_id) } } } } } pub mod persist_pullup { pub use std :: cell :: RefCell ; pub use std :: collections :: HashSet ; pub use std :: ops :: Deref ; pub use crate :: ir :: * ; pub fn persist_pullup_node < 'a > (node : & mut HfPlusNode < 'a > , seen_tees : & mut SeenTees < 'a > , persist_pulled_tees : & mut HashSet < * const RefCell < HfPlusNode < 'a > > > ,) { node . transform_children (| n , s | persist_pullup_node (n , s , persist_pulled_tees) , seen_tees ,) ; match node { HfPlusNode :: Unpersist (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Unpersist (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Delta (deref!(HfPlusNode :: Persist (_))) => { if let HfPlusNode :: Delta (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Tee { inner } => { if persist_pulled_tees . contains (& (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >)) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } else { let inner_borrow = inner . borrow () ; if let HfPlusNode :: Persist (_) = inner_borrow . deref () { drop (inner_borrow) ; persist_pulled_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >) ; if let HfPlusNode :: Persist (box behind_persist) = inner . replace (HfPlusNode :: Placeholder) { * inner . borrow_mut () = behind_persist ; } else { unreachable ! () } * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } } } HfPlusNode :: Map { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Map { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Map { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: FlatMap { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: FlatMap { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: FlatMap { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Filter { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Filter { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Filter { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Network { input : box HfPlusNode :: Persist (_) , .. } => { if let HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Union (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Union (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Union (left , right))) ; } else { unreachable ! () } } HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: CrossProduct (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,) ,)))) ; } else { unreachable ! () } } HfPlusNode :: Join (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Join (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: Join (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,))))) ; } else { unreachable ! () } } _ => { } } } pub fn persist_pullup (ir : Vec < HfPlusLeaf >) -> Vec < HfPlusLeaf > { let mut seen_tees = Default :: default () ; let mut persist_pulled_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| n , s | persist_pullup_node (n , s , & mut persist_pulled_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn persist_pullup_through_map () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } # [test] fn persist_pullup_behind_tee () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; let before_tee = flow . source_iter (& process , q ! (0 .. 10)) . tick_batch () . persist () ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } } } pub mod profiler { pub use std :: cell :: RefCell ; pub use hydroflow :: futures :: channel :: mpsc :: UnboundedSender ; pub use stageleft :: * ; pub use crate as hydroflow_plus ; pub use crate :: ir :: * ; pub use crate :: RuntimeContext ; pub fn increment_counter (count : & mut u64) { * count += 1 ; } pub fn quoted_any_fn < 'a , F : Fn (& usize) + 'a , Q : IntoQuotedMut < 'a , F > > (q : Q) -> Q { q } # [doc = " Add a profiling node before each node to count the cardinality of its input"] pub fn add_profiling_node < 'a > (node : & mut HfPlusNode < 'a > , _context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > , id : & mut u32 , seen_tees : & mut SeenTees < 'a > ,) { let my_id = * id ; * id += 1 ; node . transform_children (| node , seen_tees | { add_profiling_node (node , _context , counters , counter_queue , id , seen_tees) } , seen_tees ,) ; let orig_node = std :: mem :: replace (node , HfPlusNode :: Placeholder) ; * node = HfPlusNode :: Inspect { f : quoted_any_fn (q ! ({ counter_queue . borrow () . unbounded_send ((my_id as usize , counters . borrow () [my_id as usize])) . unwrap () ; counters . borrow_mut () [my_id as usize] = 0 ; move | _ | { hydroflow_plus :: profiler :: increment_counter (& mut counters . borrow_mut () [my_id as usize] ,) ; } })) . splice () . into () , input : Box :: new (orig_node) , } } # [doc = " Count the cardinality of each input and periodically output to a file"] pub fn profiling < 'a > (ir : Vec < HfPlusLeaf < 'a > > , context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > ,) -> Vec < HfPlusLeaf < 'a > > { let mut id = 0 ; let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | { add_profiling_node (node , context , counters , counter_queue , & mut id , seen_tees) } , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn profiler_wrapping_all_operators () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let runtime_context = flow . runtime_context () ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (& built . ir ()) ; let counters = RuntimeData :: new ("Fake") ; let counter_queue = RuntimeData :: new ("Fake") ; let pushed_down = built . with_default_optimize () . optimize_with (| ir | super :: profiling (ir , runtime_context , counters , counter_queue)) ; insta :: assert_debug_snapshot ! (& pushed_down . ir ()) ; let _ = pushed_down . compile_no_network :: < MultiGraph > () ; } } } pub mod properties { pub use std :: collections :: HashSet ; pub use stageleft :: * ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , SeenTees } ; pub use crate :: properties :: PropertyDatabase ; # [doc = " Allows us to convert the hydroflow datatype for folds to a binary operation for the algebra"] # [doc = " property tests."] # [allow (dead_code)] pub fn convert_hf_to_binary < I , A : Default , F : Fn (& mut A , I) > (f : F) -> impl Fn (I , I) -> A { move | a , b | { let mut acc = Default :: default () ; f (& mut acc , a) ; f (& mut acc , b) ; acc } } # [cfg (stageleft_macro)] impl PropertyDatabase { # [doc = " Tags the expression as commutative."] pub fn add_commutative_tag < 'a , I , A , F : Fn (& mut A , I) , Q : Quoted < 'a , F > + Clone > (& mut self , expr : Q ,) -> Q { let expr_clone = expr . clone () ; self . commutative . insert (expr_clone . splice ()) ; expr } pub fn is_tagged_commutative (& self , expr : & syn :: Expr) -> bool { self . commutative . contains (expr) } } pub fn properties_optimize_node < 'a > (node : & mut HfPlusNode < 'a > , db : & PropertyDatabase , seen_tees : & mut SeenTees < 'a > ,) { node . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , seen_tees ,) ; match node { HfPlusNode :: ReduceKeyed { f , .. } if db . is_tagged_commutative (& f . 0) => { dbg ! ("IDENTIFIED COMMUTATIVE OPTIMIZATION for {:?}" , & f) ; } _ => { } } } pub fn properties_optimize < 'a > (ir : Vec < HfPlusLeaf < 'a > > , db : & PropertyDatabase ,) -> Vec < HfPlusLeaf < 'a > > { let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use super :: * ; use crate :: deploy :: SingleProcessGraph ; use crate :: FlowBuilder ; # [test] fn test_property_database () { let mut db = PropertyDatabase :: default () ; assert ! (! db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; let _ = db . add_commutative_tag (q ! (| a : & mut i32 , b : i32 | * a += b)) ; assert ! (db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; } # [test] fn test_property_optimized () { let flow = FlowBuilder :: new () ; let mut database = PropertyDatabase :: default () ; let process = flow . process :: < () > () ; let counter_func = q ! (| count : & mut i32 , _ | * count += 1) ; let _ = database . add_commutative_tag (counter_func) ; flow . source_iter (& process , q ! (vec ! [])) . map (q ! (| string : String | (string , ()))) . tick_batch () . fold_keyed (q ! (|| 0) , counter_func) . all_ticks () . for_each (q ! (| (string , count) | println ! ("{}: {}" , string , count))) ; let built = flow . finalize () . optimize_with (| ir | properties_optimize (ir , & database)) . with_default_optimize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let _ = built . compile_no_network :: < SingleProcessGraph > () ; } } } pub use crate :: RuntimeContext ; # [cfg (stageleft_macro)] impl Copy for RuntimeContext < '_ > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Context > for RuntimeContext < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (quote ! (& context))) } } pub use crate :: HfCompiled ; # [cfg (stageleft_macro)] impl < 'a , ID > HfCompiled < 'a , ID > { pub fn hydroflow_ir (& self) -> & BTreeMap < usize , HydroflowGraph > { & self . hydroflow_ir } } # [cfg (stageleft_macro)] impl < 'a > HfCompiled < 'a , usize > { pub fn with_dynamic_id (self , id : impl Quoted < 'a , usize >) -> HfBuiltWithId < 'a > { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; let mut conditioned_tokens = None ; for (subgraph_id , flat_graph) in self . hydroflow_ir { let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; let my_extra_stmts = self . extra_stmts . get (& subgraph_id) . cloned () . unwrap_or_default () ; if let Some (conditioned_tokens) = conditioned_tokens . as_mut () { * conditioned_tokens = syn :: parse_quote ! { # conditioned_tokens else if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } } ; } else { conditioned_tokens = Some (syn :: parse_quote ! { if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } }) ; } } let conditioned_tokens : TokenStream = conditioned_tokens . unwrap () ; let id = id . splice () ; HfBuiltWithId { tokens : syn :: parse_quote ! ({ let __given_id = # id ; # conditioned_tokens else { panic ! ("Invalid node id: {}" , __given_id) ; } }) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfCompiled < 'a , () > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfCompiled < 'a , () > { fn to_tokens (mut self) -> (Option < TokenStream > , Option < TokenStream >) { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; if self . hydroflow_ir . len () != 1 { panic ! ("Expected exactly one subgraph in the Hydroflow IR") ; } let flat_graph = self . hydroflow_ir . remove (& 0) . unwrap () ; let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; (None , Some (tokens)) } } pub use crate :: HfBuiltWithId ; # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfBuiltWithId < 'a > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfBuiltWithId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (self . tokens)) } }
[INFO] [stdout]   |
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] error: `box` patterns have been removed (feature `box_patterns`)
[INFO] [stdout]  --> /opt/rustwide/target/debug/build/hydroflow_plus/5672655b657d1e44/out/lib_pub.rs:1:92128
[INFO] [stdout]   |
[INFO] [stdout] 1 | ...)) => { if let HfPlusNode :: Delta (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: ...
[INFO] [stdout]   |                                                                   ^^^
[INFO] [stdout]   |
[INFO] [stdout]   = help: enable feature `deref_patterns` instead and...
[INFO] [stdout] help: ...if possible just remove keyword `box`...
[INFO] [stdout]   |
[INFO] [stdout] 1 - pub use std :: collections :: BTreeMap ; pub use std :: marker :: PhantomData ; pub use hydroflow :: scheduled :: context :: Context ; pub use hydroflow :: scheduled :: graph :: Hydroflow ; pub use hydroflow :: * ; pub use lang :: graph :: { partition_graph , HydroflowGraph } ; pub use proc_macro2 :: TokenStream ; pub use quote :: quote ; pub use stageleft :: runtime_support :: FreeVariable ; pub use stageleft :: Quoted ; pub mod runtime_support { pub use bincode ; } pub mod stream { pub use std :: cell :: RefCell ; pub use std :: hash :: Hash ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow :: bytes :: Bytes ; pub use hydroflow :: futures :: Sink ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: quote ; pub use serde :: de :: DeserializeOwned ; pub use serde :: Serialize ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use syn :: parse_quote ; pub use crate :: builder :: { ClusterIds , FlowLeaves } ; pub use crate :: cycle :: { CycleCollection , CycleComplete } ; pub use crate :: ir :: { DebugInstantiate , HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { CanSend , Location , LocationId } ; pub use crate :: { Cluster , Optional , Singleton } ; pub use crate :: stream :: Unbounded ; pub use crate :: stream :: Bounded ; pub use crate :: stream :: NoTick ; pub use crate :: stream :: Tick ; pub use crate :: stream :: Stream ; # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Stream { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Stream < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Stream { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , C , N > > ,) -> Stream < 'a , (T , O) , W , C , N > where O : Clone , { let other : Optional < 'a , O , Bounded , C , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn cross_product < O > (self , other : Stream < 'a , O , W , C , N >) -> Stream < 'a , (T , O) , W , C , N > where T : Clone , O : Clone , { if self . location_kind != other . location_kind { panic ! ("cross_product must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossProduct (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn union (self , other : Stream < 'a , T , W , C , N >) -> Stream < 'a , T , W , C , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn dest_sink < S : Unpin + Sink < T > + 'a > (self , sink : impl Quoted < 'a , S >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: DestSink { sink : sink . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn first (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } # [doc = " Allow this stream through if the other stream has elements, otherwise the output is empty."] pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } # [doc = " Allow this stream through if the other stream is empty, otherwise the output is empty."] pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn enumerate (self) -> Stream < 'a , (usize , T) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Enumerate (Box :: new (self . ir_node . into_inner ())) ,) } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn sort (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Ord , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Sort (Box :: new (self . ir_node . into_inner ())) ,) } pub fn count (self) -> Singleton < 'a , usize , Bounded , Tick , N > { self . fold (q ! (|| 0usize) , q ! (| count , _ | * count += 1)) } pub fn delta (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } pub fn unique (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Eq + Hash , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unique (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn tick_batch (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_prefix (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { self . tick_batch () . persist () } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn for_each < F : Fn (T) + 'a > (self , f : impl IntoQuotedMut < 'a , F >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: ForEach { input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , f : f . splice () . into () , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Unbounded , NoTick , N > { pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . tick_batch () . continue_if (samples . first ()) . all_ticks () } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Unbounded , NoTick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , C , N : Location > Stream < 'a , T , Bounded , C , N > { pub fn filter_not_in (self , other : Stream < 'a , T , Bounded , C , N >) -> Stream < 'a , T , Bounded , C , N > where T : Eq + Hash , { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Difference (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Stream < 'a , & T , W , C , N > { pub fn cloned (self) -> Stream < 'a , T , W , C , N > { self . map (q ! (| d | d . clone ())) } } # [cfg (stageleft_macro)] impl < 'a , K , V1 , W , C , N : Location > Stream < 'a , (K , V1) , W , C , N > { pub fn join < W2 , V2 > (self , n : Stream < 'a , (K , V2) , W2 , C , N > ,) -> Stream < 'a , (K , (V1 , V2)) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Join (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } pub fn anti_join < W2 > (self , n : Stream < 'a , K , W2 , C , N >) -> Stream < 'a , (K , V1) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("anti_join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: AntiJoin (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , K : Eq + Hash , V , N : Location > Stream < 'a , (K , V) , Bounded , Tick , N > { pub fn fold_keyed < A , I : Fn () -> A + 'a , F : Fn (& mut A , V) + 'a > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , A) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FoldKeyed { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce_keyed < F : Fn (& mut V , V) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , V) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: ReduceKeyed { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } pub fn get_this_crate () -> TokenStream { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , Span :: call_site ()) ; quote ! { # ident } } } } pub fn serialize_bincode < T : Serialize > (is_demux : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if is_demux { parse_quote ! { map (| (id , data) | { (id , # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into ()) }) } } else { parse_quote ! { map (| data | { # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into () }) } } } pub fn deserialize_bincode < T : DeserializeOwned > (tagged : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if tagged { parse_quote ! { map (| res | { let (id , b) = res . unwrap () ; (id , # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& b) . unwrap ()) }) } } else { parse_quote ! { map (| res | { # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& res . unwrap ()) . unwrap () }) } } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn send_bincode < N2 : Location , CoreType > (self , other : & N2 ,) -> Stream < 'a , N :: Out < CoreType > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T > , CoreType : Serialize + DeserializeOwned , { let serialize_pipeline = Some (serialize_bincode :: < CoreType > (N :: is_demux ())) ; let deserialize_pipeline = Some (deserialize_bincode :: < CoreType > (N :: is_tagged ())) ; Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bytes < N2 : Location > (self , other : & N2 ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T > , { Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline : None , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline : if N :: is_tagged () { Some (parse_quote ! (map (| (id , b) | (id , b . unwrap () . freeze ())))) } else { Some (parse_quote ! (map (| b | b . unwrap () . freeze ()))) } , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bincode_interleaved < N2 : Location , Tag , CoreType > (self , other : & N2 ,) -> Stream < 'a , CoreType , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T , Out < CoreType > = (Tag , CoreType) > , CoreType : Serialize + DeserializeOwned , { self . send_bincode :: < N2 , CoreType > (other) . map (q ! (| (_ , b) | b)) } pub fn send_bytes_interleaved < N2 : Location , Tag > (self , other : & N2 ,) -> Stream < 'a , Bytes , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T , Out < Bytes > = (Tag , Bytes) > , { self . send_bytes :: < N2 > (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bincode < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < T > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) > , T : Clone + Serialize + DeserializeOwned , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bincode (other) } pub fn broadcast_bincode_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , T , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) , Out < T > = (Tag , T) > + 'a , T : Clone + Serialize + DeserializeOwned , { self . broadcast_bincode (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bytes < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) > + 'a , T : Clone , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bytes (other) } pub fn broadcast_bytes_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , Bytes , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) , Out < Bytes > = (Tag , Bytes) > + 'a , T : Clone , { self . broadcast_bytes (other) . map (q ! (| (_ , b) | b)) } } } pub use stream :: { Bounded , NoTick , Stream , Tick , Unbounded } ; pub mod singleton { pub use std :: cell :: RefCell ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use crate :: builder :: FlowLeaves ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial , CycleComplete } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: Stream ; pub use crate :: singleton :: CrossResult ; # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Singleton < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Singleton :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } pub use crate :: singleton :: Singleton ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Singleton { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleComplete < 'a > for Singleton < 'a , T , Bounded , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleCollectionWithInitial < 'a > for Singleton < 'a , T , Bounded , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , initial : Self , l : LocationId ,) -> Self { Singleton :: new (l , ir_leaves , HfPlusNode :: Union (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , }) , initial . ir_node . into_inner () . into () ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Singleton < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Singleton { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , U , W , C , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (Self :: other_ir_node (other)) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Singleton < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CrossSingleton (Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , Box :: new (HfPlusNode :: Unpersist (Box :: new (Self :: other_ir_node (other)))) ,))) ,) } } pub use crate :: singleton :: Optional ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Optional { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } pub fn some (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: new (singleton . location_kind , singleton . ir_leaves , singleton . ir_node . into_inner () ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > From < Singleton < 'a , T , W , C , N > > for Optional < 'a , T , W , C , N > { fn from (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: some (singleton) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Optional < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Optional { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn into_stream (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , Tick , N > > ,) -> Optional < 'a , (T , O) , Bounded , Tick , N > where O : Clone , { let other : Optional < 'a , O , Bounded , Tick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn union (self , other : Optional < 'a , T , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Optional < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_samples (self) -> Stream < 'a , T , Unbounded , NoTick , N > { self . latest_tick () . all_ticks () } pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . latest_tick () . continue_if (samples . first ()) . latest () . tick_samples () } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Unbounded , NoTick , N > > ,) -> Optional < 'a , (T , O) , Unbounded , NoTick , N > where O : Clone , { let other : Optional < 'a , O , Unbounded , NoTick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } self . latest_tick () . cross_singleton (other . latest_tick ()) . latest () } } } pub use singleton :: { Optional , Singleton } ; pub mod location { pub use std :: marker :: PhantomData ; pub use crate :: location :: LocationId ; pub use crate :: location :: Location ; pub use crate :: location :: Process ; # [cfg (stageleft_macro)] impl < P > Clone for Process < P > { fn clone (& self) -> Self { Process { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < P > Location for Process < P > { fn id (& self) -> LocationId { LocationId :: Process (self . id) } } pub use crate :: location :: Cluster ; # [cfg (stageleft_macro)] impl < C > Clone for Cluster < C > { fn clone (& self) -> Self { Cluster { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < C > Location for Cluster < C > { fn id (& self) -> LocationId { LocationId :: Cluster (self . id) } } pub use crate :: location :: CanSend ; # [cfg (stageleft_macro)] impl < P1 , P2 > CanSend < Process < P2 > > for Process < P1 > { type In < T > = T ; type Out < T > = T ; fn is_demux () -> bool { false } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < P1 , C2 > CanSend < Cluster < C2 > > for Process < P1 > { type In < T > = (u32 , T) ; type Out < T > = T ; fn is_demux () -> bool { true } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < C1 , P2 > CanSend < Process < P2 > > for Cluster < C1 > { type In < T > = T ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { false } fn is_tagged () -> bool { true } } # [cfg (stageleft_macro)] impl < C1 , C2 > CanSend < Cluster < C2 > > for Cluster < C1 > { type In < T > = (u32 , T) ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { true } fn is_tagged () -> bool { true } } } pub use location :: { Cluster , Process } ; pub mod deploy { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use stageleft :: Quoted ; pub mod graphs { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use super :: { LocalDeploy , Node , ProcessSpec } ; pub use crate :: deploy :: graphs :: SingleProcessGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for SingleProcessGraph { type Process = SingleNode ; type Cluster = SingleNode ; type Meta = () ; type GraphId = () ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { SingleNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { SingleNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , SingleProcessGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> SingleNode { SingleNode { } } } pub use crate :: deploy :: graphs :: SingleNode ; # [cfg (stageleft_macro)] impl Node for SingleNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } pub use crate :: deploy :: graphs :: MultiGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for MultiGraph { type Process = MultiNode ; type Cluster = MultiNode ; type Meta = () ; type GraphId = usize ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { MultiNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { MultiNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , MultiGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> MultiNode { MultiNode { } } } pub use crate :: deploy :: graphs :: MultiNode ; # [cfg (stageleft_macro)] impl Node for MultiNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } } pub use graphs :: * ; pub use crate :: deploy :: LocalDeploy ; pub use crate :: deploy :: Deploy ; # [cfg (stageleft_macro)] impl < 'a , T : Deploy < 'a , Process = N , Cluster = C , Meta = M , GraphId = R > , N : Node < Meta = M > , C : Node < Meta = M > , M : Default , R , > LocalDeploy < 'a > for T { type Process = N ; type Cluster = C ; type Meta = M ; type GraphId = R ; fn has_trivial_node () -> bool { < T as Deploy < 'a > > :: has_trivial_node () } fn trivial_process (id : usize) -> Self :: Process { < T as Deploy < 'a > > :: trivial_process (id) } fn trivial_cluster (id : usize) -> Self :: Cluster { < T as Deploy < 'a > > :: trivail_cluster (id) } } pub use crate :: deploy :: ProcessSpec ; pub use crate :: deploy :: ClusterSpec ; pub use crate :: deploy :: Node ; } pub use deploy :: { ClusterSpec , Deploy , ProcessSpec } ; pub mod cycle { pub use std :: marker :: PhantomData ; pub use crate :: builder :: FlowLeaves ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: cycle :: CycleComplete ; pub use crate :: cycle :: CycleCollection ; pub use crate :: cycle :: CycleCollectionWithInitial ; pub use crate :: cycle :: HfCycle ; # [cfg (stageleft_macro)] impl < 'a , S : CycleComplete < 'a > > HfCycle < 'a , S > { pub fn complete (self , stream : S) { let ident = self . ident ; S :: complete (stream , ident) } } } pub use cycle :: HfCycle ; pub mod builder { pub use std :: cell :: RefCell ; pub use std :: collections :: HashMap ; pub use std :: marker :: PhantomData ; pub use std :: rc :: Rc ; pub use std :: time :: Duration ; pub use hydroflow :: futures :: stream :: Stream as FuturesStream ; pub use hydroflow :: { tokio , tokio_stream } ; pub use internal :: TokenStream ; pub use proc_macro2 :: Span ; pub use quote :: quote ; pub use runtime_support :: FreeVariable ; pub use stageleft :: * ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Cluster , Location , LocationId , Process } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: { HfCycle , Optional , RuntimeContext , Singleton , Stream } ; pub mod built { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use hydroflow_lang :: graph :: { eliminate_extra_unions_tees , HydroflowGraph } ; pub use super :: deploy :: { DeployFlow , DeployResult } ; pub use crate :: deploy :: { ClusterSpec , Deploy , LocalDeploy , ProcessSpec } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Cluster , Process } ; pub use crate :: HfCompiled ; pub use crate :: builder :: built :: BuiltFlow ; # [cfg (stageleft_macro)] impl < 'a > Drop for BuiltFlow < 'a > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped BuiltFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn ir (& self) -> & Vec < HfPlusLeaf < 'a > > { & self . ir } pub fn optimize_with (mut self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> BuiltFlow < 'a > { self . used = true ; BuiltFlow { ir : f (std :: mem :: take (& mut self . ir)) , processes : std :: mem :: take (& mut self . processes) , clusters : std :: mem :: take (& mut self . clusters) , used : false , _phantom : PhantomData , } } } pub fn build_inner (ir : & mut Vec < HfPlusLeaf >) -> BTreeMap < usize , HydroflowGraph > { let mut builders = BTreeMap :: new () ; let mut built_tees = HashMap :: new () ; let mut next_stmt_id = 0 ; for leaf in ir { leaf . emit (& mut builders , & mut built_tees , & mut next_stmt_id) ; } builders . into_iter () . map (| (k , v) | { let (mut flat_graph , _ , _) = v . build () ; eliminate_extra_unions_tees (& mut flat_graph) ; (k , flat_graph) }) . collect () } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn compile_no_network < D : LocalDeploy < 'a > > (mut self) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; HfCompiled { hydroflow_ir : build_inner (& mut self . ir) , extra_stmts : BTreeMap :: new () , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> BuiltFlow < 'a > { self . optimize_with (crate :: persist_pullup :: persist_pullup) } fn into_deploy < D : LocalDeploy < 'a > > (mut self) -> DeployFlow < 'a , D > { self . used = true ; let processes = if D :: has_trivial_node () { self . processes . iter () . map (| id | (* id , D :: trivial_process (* id))) . collect () } else { HashMap :: new () } ; let clusters = if D :: has_trivial_node () { self . clusters . iter () . map (| id | (* id , D :: trivial_cluster (* id))) . collect () } else { HashMap :: new () } ; DeployFlow { ir : std :: mem :: take (& mut self . ir) , nodes : processes , clusters , used : false , _phantom : PhantomData , } } pub fn with_process < P , D : LocalDeploy < 'a > > (self , process : & Process < P > , spec : impl ProcessSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_process (process , spec) } pub fn with_cluster < C , D : LocalDeploy < 'a > > (self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_cluster (cluster , spec) } pub fn compile < D : Deploy < 'a > + 'a > (self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . into_deploy :: < D > () . compile (env) } pub fn deploy < D : Deploy < 'a , CompileEnv = () > + 'a > (self , env : & mut D :: InstantiateEnv ,) -> DeployResult < 'a , D > { self . into_deploy :: < D > () . deploy (env) } } } pub mod deploy { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use proc_macro2 :: Span ; pub use stageleft :: Quoted ; pub use super :: built :: build_inner ; pub use crate :: deploy :: { LocalDeploy , Node } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: { Cluster , ClusterSpec , Deploy , HfCompiled , Process , ProcessSpec } ; pub use crate :: builder :: deploy :: DeployFlow ; # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > Drop for DeployFlow < 'a , D > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped DeployFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > DeployFlow < 'a , D > { pub fn with_process < P > (mut self , process : & Process < P > , spec : impl ProcessSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < P > () . to_string () ; self . nodes . insert (process . id , spec . build (process . id , & tag_name)) ; self } pub fn with_cluster < C > (mut self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < C > () . to_string () ; self . clusters . insert (cluster . id , spec . build (cluster . id , & tag_name)) ; self } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployFlow < 'a , D > { pub fn compile (mut self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; let mut seen_tees : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | leaf . compile_network :: < D > (env , & mut seen_tees , & self . nodes , & self . clusters)) . collect () ; let extra_stmts = self . extra_stmts (env) ; HfCompiled { hydroflow_ir : build_inner (& mut ir_leaves_networked) , extra_stmts , _phantom : PhantomData , } } fn extra_stmts (& self , env : & < D as Deploy < 'a > > :: CompileEnv) -> BTreeMap < usize , Vec < syn :: Stmt > > { let all_locations_count = self . nodes . len () + self . clusters . len () ; let mut extra_stmts : BTreeMap < usize , Vec < syn :: Stmt > > = BTreeMap :: new () ; for & c_id in self . clusters . keys () { let self_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , c_id) , Span :: call_site () ,) ; let self_id_expr = D :: cluster_self_id (env) . splice () ; extra_stmts . entry (c_id) . or_default () . push (syn :: parse_quote ! { let # self_id_ident = # self_id_expr ; }) ; for other_location in 0 .. all_locations_count { let other_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , c_id) , Span :: call_site () ,) ; let other_id_expr = D :: cluster_ids (env , c_id) . splice () ; extra_stmts . entry (other_location) . or_default () . push (syn :: parse_quote ! { let # other_id_ident = # other_id_expr ; }) ; } } extra_stmts } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a , CompileEnv = () > > DeployFlow < 'a , D > { # [must_use] pub fn deploy (mut self , env : & mut D :: InstantiateEnv) -> DeployResult < 'a , D > { self . used = true ; let mut seen_tees_instantiate : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | { leaf . compile_network :: < D > (& () , & mut seen_tees_instantiate , & self . nodes , & self . clusters ,) }) . collect () ; let mut compiled = build_inner (& mut ir_leaves_networked) ; let mut extra_stmts = self . extra_stmts (& ()) ; let mut meta = D :: Meta :: default () ; let (mut processes , mut clusters) = (std :: mem :: take (& mut self . nodes) . into_iter () . map (| (node_id , node) | { node . instantiate (env , & mut meta , compiled . remove (& node_id) . unwrap () , extra_stmts . remove (& node_id) . unwrap_or_default () ,) ; (node_id , node) }) . collect :: < HashMap < _ , _ > > () , std :: mem :: take (& mut self . clusters) . into_iter () . map (| (cluster_id , cluster) | { cluster . instantiate (env , & mut meta , compiled . remove (& cluster_id) . unwrap () , extra_stmts . remove (& cluster_id) . unwrap_or_default () ,) ; (cluster_id , cluster) }) . collect :: < HashMap < _ , _ > > () ,) ; for node in processes . values_mut () { node . update_meta (& meta) ; } for cluster in clusters . values_mut () { cluster . update_meta (& meta) ; } let mut seen_tees_connect = HashMap :: new () ; for leaf in ir_leaves_networked { leaf . connect_network (& mut seen_tees_connect) ; } DeployResult { processes , clusters , } } } pub use crate :: builder :: deploy :: DeployResult ; # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployResult < 'a , D > { pub fn get_process < P > (& self , p : & Process < P >) -> & D :: Process { let id = match p . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . processes . get (& id) . unwrap () } pub fn get_cluster < C > (& self , c : & Cluster < C >) -> & D :: Cluster { let id = match c . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . clusters . get (& id) . unwrap () } } } # [doc = " Tracks the leaves of the dataflow IR. This is referenced by"] # [doc = " `Stream` and `HfCycle` to build the IR. The inner option will"] # [doc = " be set to `None` when this builder is finalized."] pub type FlowLeaves < 'a > = Rc < RefCell < Option < Vec < HfPlusLeaf < 'a > > > > > ; pub use crate :: builder :: ClusterIds ; # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Vec < u32 > > for ClusterIds < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , & 'a Vec < u32 > > for ClusterIds < 'a > { } # [derive (Copy , Clone)] pub struct ClusterSelfId < 'a > { pub id : usize , pub _phantom : PhantomData < & 'a mut & 'a u32 > , } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < u32 > for ClusterSelfId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , u32 > for ClusterSelfId < 'a > { } pub use crate :: builder :: FlowBuilder ; # [cfg (stageleft_macro)] impl < 'a > Drop for FlowBuilder < 'a > { fn drop (& mut self) { if ! self . finalized { panic ! ("Dropped FlowBuilder without finalizing, you may have forgotten to call `with_default_optimize`, `optimize_with`, or `finalize`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > QuotedContext for FlowBuilder < 'a > { fn create () -> Self { FlowBuilder :: new () } } # [cfg (stageleft_macro)] impl < 'a > FlowBuilder < 'a > { # [allow (clippy :: new_without_default)] pub fn new () -> FlowBuilder < 'a > { FlowBuilder { ir_leaves : Rc :: new (RefCell :: new (Some (Vec :: new ()))) , nodes : RefCell :: new (vec ! []) , clusters : RefCell :: new (vec ! []) , cycle_ids : RefCell :: new (HashMap :: new ()) , next_node_id : RefCell :: new (0) , finalized : false , _phantom : PhantomData , } } pub fn finalize (mut self) -> built :: BuiltFlow < 'a > { self . finalized = true ; built :: BuiltFlow { ir : self . ir_leaves . borrow_mut () . take () . unwrap () , processes : self . nodes . replace (vec ! []) , clusters : self . clusters . replace (vec ! []) , used : false , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> built :: BuiltFlow < 'a > { self . finalize () . with_default_optimize () } pub fn optimize_with (self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> built :: BuiltFlow < 'a > { self . finalize () . optimize_with (f) } pub fn ir_leaves (& self) -> & FlowLeaves < 'a > { & self . ir_leaves } pub fn process < P > (& self) -> Process < P > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . nodes . borrow_mut () . push (id) ; Process { id , _phantom : PhantomData , } } pub fn cluster < C > (& self) -> Cluster < C > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . clusters . borrow_mut () . push (id) ; Cluster { id , _phantom : PhantomData , } } pub fn runtime_context (& self) -> RuntimeContext < 'a > { RuntimeContext { _phantom : PhantomData , } } pub fn cluster_members < C > (& self , cluster : & Cluster < C > ,) -> impl Quoted < 'a , & 'a Vec < u32 > > + Copy + 'a { ClusterIds { id : cluster . id , _phantom : PhantomData , } } pub fn cluster_self_id < C > (& self , cluster : & Cluster < C >) -> impl Quoted < 'a , u32 > + Copy + 'a { ClusterSelfId { id : cluster . id , _phantom : PhantomData , } } pub fn spin < L : Location > (& self , on : & L) -> Stream < 'a , () , Unbounded , NoTick , L > { Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Spin () , location_kind : on . id () , })) ,) } pub fn spin_batch < L : Location > (& self , on : & L , batch_size : impl Quoted < 'a , usize > + Copy + 'a ,) -> Stream < 'a , () , Bounded , Tick , L > { self . spin (on) . flat_map (q ! (move | _ | 0 .. batch_size)) . map (q ! (| _ | ())) . tick_batch () } pub fn source_stream < T , E : FuturesStream < Item = T > + Unpin , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Unbounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Stream (e . into ()) , location_kind : on . id () , })) ,) } pub fn source_iter < T , E : IntoIterator < Item = T > , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Bounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , })) ,) } pub fn singleton < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Singleton < 'a , T , Bounded , NoTick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Singleton :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,)))) ,) } pub fn singleton_first_tick < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Optional < 'a , T , Bounded , Tick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,) } pub fn source_interval < L : Location > (& self , on : & L , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , () , Unbounded , NoTick , L > { let interval = interval . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : on . id () , })) ,) } pub fn source_interval_delayed < L : Location > (& self , on : & L , delay : impl Quoted < 'a , Duration > + Copy + 'a , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , tokio :: time :: Instant , Unbounded , NoTick , L > { self . source_stream (on , q ! (tokio_stream :: wrappers :: IntervalStream :: new (tokio :: time :: interval_at (tokio :: time :: Instant :: now () + delay , interval))) ,) . tick_batch () . first () . latest () } pub fn cycle < S : CycleCollection < 'a > > (& self , on : & S :: Location) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , on . id ()) ,) } pub fn cycle_with_initial < S : CycleCollectionWithInitial < 'a > > (& self , on : & S :: Location , initial : S ,) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , initial , on . id ()) ,) } } } pub use builder :: FlowBuilder ; pub mod ir { pub use core :: panic ; pub use std :: cell :: RefCell ; pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow_lang :: graph :: FlatGraphBuilder ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: ToTokens ; pub use syn :: parse_quote ; pub use crate :: deploy :: Deploy ; pub use crate :: location :: LocationId ; pub use crate :: ir :: DebugExpr ; # [cfg (stageleft_macro)] impl From < syn :: Expr > for DebugExpr { fn from (expr : syn :: Expr) -> DebugExpr { DebugExpr (expr) } } # [cfg (stageleft_macro)] impl Deref for DebugExpr { type Target = syn :: Expr ; fn deref (& self) -> & Self :: Target { & self . 0 } } # [cfg (stageleft_macro)] impl ToTokens for DebugExpr { fn to_tokens (& self , tokens : & mut TokenStream) { self . 0 . to_tokens (tokens) ; } } # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugExpr { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "{}" , self . 0 . to_token_stream ()) } } pub use crate :: ir :: DebugInstantiate ; # [cfg (stageleft_macro)] impl < 'a > std :: fmt :: Debug for DebugInstantiate < 'a > { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<network instantiate>") } } pub use crate :: ir :: DebugPipelineFn ; # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugPipelineFn { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<function>") } } pub use crate :: ir :: HfPlusSource ; pub use crate :: ir :: HfPlusLeaf ; # [cfg (stageleft_macro)] impl < 'a > HfPlusLeaf < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . compile_network :: < D > (compile_env , s , nodes , clusters) ; } , seen_tees ,) } pub fn connect_network (self , seen_tees : & mut SeenTees < 'a >) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . connect_network (s) ; } , seen_tees ,) } pub fn transform_children (self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) -> HfPlusLeaf < 'a > { match self { HfPlusLeaf :: ForEach { f , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: ForEach { f , input } } HfPlusLeaf :: DestSink { sink , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: DestSink { sink , input } } HfPlusLeaf :: CycleSink { ident , location_kind , mut input , } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: CycleSink { ident , location_kind , input , } } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) { match self { HfPlusLeaf :: ForEach { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> for_each (# f) ; }) ; } HfPlusLeaf :: DestSink { sink , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink) ; }) ; } HfPlusLeaf :: CycleSink { ident , location_kind , input , } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; assert_eq ! (input_location_id , * location_id , "cycle_sink location mismatch") ; graph_builders . entry (* location_id) . or_default () . add_statement (parse_quote ! { # ident = # input_ident ; }) ; } } } } pub use crate :: ir :: HfPlusNode ; pub type SeenTees < 'a > = HashMap < * const RefCell < HfPlusNode < 'a > > , Rc < RefCell < HfPlusNode < 'a > > > > ; # [cfg (stageleft_macro)] impl < 'a > HfPlusNode < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (& mut self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) { self . transform_children (| n , s | n . compile_network :: < D > (compile_env , s , nodes , clusters) , seen_tees ,) ; if let HfPlusNode :: Network { from_location , to_location , instantiate_fn , .. } = self { let (sink_expr , source_expr , connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { let ((sink , source) , connect_fn) = match (from_location , to_location) { (LocationId :: Process (from) , LocationId :: Process (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: o2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Process (from) , LocationId :: Cluster (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: o2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Process (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: m2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Cluster (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: m2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } } ; (sink , source , connect_fn) } DebugInstantiate :: Finalized (_ , _ , _) => panic ! ("network already finalized") , } ; * instantiate_fn = DebugInstantiate :: Finalized (sink_expr , source_expr , connect_fn) ; } } pub fn connect_network (& mut self , seen_tees : & mut SeenTees < 'a >) { self . transform_children (| n , s | n . connect_network (s) , seen_tees) ; if let HfPlusNode :: Network { instantiate_fn , .. } = self { match instantiate_fn { DebugInstantiate :: Building () => panic ! ("network not built") , DebugInstantiate :: Finalized (_ , _ , ref connect_fn) => { connect_fn () ; } } } } pub fn transform_children (& mut self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) { match self { HfPlusNode :: Placeholder => { panic ! () ; } HfPlusNode :: Source { .. } => { } HfPlusNode :: CycleSource { .. } => { } HfPlusNode :: Tee { inner } => { if let Some (transformed) = seen_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { * inner = transformed . clone () ; } else { let transformed_cell = Rc :: new (RefCell :: new (HfPlusNode :: Placeholder)) ; seen_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , transformed_cell . clone () ,) ; let mut orig = inner . replace (HfPlusNode :: Placeholder) ; transform (& mut orig , seen_tees) ; * transformed_cell . borrow_mut () = orig ; * inner = transformed_cell ; } } HfPlusNode :: Persist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Unpersist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Delta (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Union (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossProduct (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossSingleton (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Join (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Difference (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: AntiJoin (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Map { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FlatMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Filter { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FilterMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Sort (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: DeferTick (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Enumerate (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Inspect { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Unique (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Fold { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FoldKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Reduce { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: ReduceKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Network { input , .. } => { transform (input . as_mut () , seen_tees) ; } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) -> (syn :: Ident , usize) { match self { HfPlusNode :: Placeholder => { panic ! () } HfPlusNode :: Persist (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let persist_id = * next_stmt_id ; * next_stmt_id += 1 ; let persist_ident = syn :: Ident :: new (& format ! ("stream_{}" , persist_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # persist_ident = # inner_ident -> persist ::<'static > () ; }) ; (persist_ident , location) } HfPlusNode :: Unpersist (_) => { panic ! ("Unpersist is a marker node and should have been optimized away. This is likely a compiler bug.") } HfPlusNode :: Delta (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let delta_id = * next_stmt_id ; * next_stmt_id += 1 ; let delta_ident = syn :: Ident :: new (& format ! ("stream_{}" , delta_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # delta_ident = # inner_ident -> multiset_delta () ; }) ; (delta_ident , location) } HfPlusNode :: Source { source , location_kind , } => { let source_id = * next_stmt_id ; * next_stmt_id += 1 ; let source_ident = syn :: Ident :: new (& format ! ("stream_{}" , source_id) , Span :: call_site ()) ; let source_stmt = match source { HfPlusSource :: Stream (expr) => { parse_quote ! { # source_ident = source_stream (# expr) ; } } HfPlusSource :: Iter (expr) => { parse_quote ! { # source_ident = source_iter (# expr) ; } } HfPlusSource :: Interval (expr) => { parse_quote ! { # source_ident = source_interval (# expr) ; } } HfPlusSource :: Spin () => { parse_quote ! { # source_ident = spin () ; } } } ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; graph_builders . entry (* location_id) . or_default () . add_statement (source_stmt) ; (source_ident , * location_id) } HfPlusNode :: CycleSource { ident , location_kind , } => { let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; (ident . clone () , * location_id) } HfPlusNode :: Tee { inner } => { if let Some (ret) = built_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { ret . clone () } else { let (inner_ident , inner_location_id) = inner . borrow () . emit (graph_builders , built_tees , next_stmt_id) ; let tee_id = * next_stmt_id ; * next_stmt_id += 1 ; let tee_ident = syn :: Ident :: new (& format ! ("stream_{}" , tee_id) , Span :: call_site ()) ; let builder = graph_builders . entry (inner_location_id) . or_default () ; builder . add_statement (parse_quote ! { # tee_ident = # inner_ident -> tee () ; }) ; built_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , (tee_ident . clone () , inner_location_id) ,) ; (tee_ident , inner_location_id) } } HfPlusNode :: Union (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "union inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let union_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # union_ident = union () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [0] # union_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # union_ident ; }) ; (union_ident , left_location_id) } HfPlusNode :: CrossSingleton (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "cross_singleton inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let cross_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # cross_ident = cross_singleton () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [input] # cross_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [single] # cross_ident ; }) ; (cross_ident , left_location_id) } HfPlusNode :: CrossProduct (..) | HfPlusNode :: Join (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: CrossProduct (..)) { parse_quote ! (cross_join_multiset) } else { parse_quote ! (join_multiset) } ; let (HfPlusNode :: CrossProduct (left , right) | HfPlusNode :: Join (left , right)) = self else { unreachable ! () } ; let (left_inner , left_was_persist) = if let HfPlusNode :: Persist (left) = left . as_ref () { (left , true) } else { (left , false) } ; let (right_inner , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left_inner . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right_inner . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "join / cross product inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; match (left_was_persist , right_was_persist) { (true , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'static > () ; }) ; } (true , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'tick > () ; }) ; } (false , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } (false , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } } ; builder . add_statement (parse_quote ! { # left_ident -> [0] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Difference (..) | HfPlusNode :: AntiJoin (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Difference (..)) { parse_quote ! (difference_multiset) } else { parse_quote ! (anti_join_multiset) } ; let (HfPlusNode :: Difference (left , right) | HfPlusNode :: AntiJoin (left , right)) = self else { unreachable ! () } ; let (right , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "difference / anti join inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; if right_was_persist { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } else { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } builder . add_statement (parse_quote ! { # left_ident -> [pos] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [neg] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Map { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let map_id = * next_stmt_id ; * next_stmt_id += 1 ; let map_ident = syn :: Ident :: new (& format ! ("stream_{}" , map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # map_ident = # input_ident -> map (# f) ; }) ; (map_ident , input_location_id) } HfPlusNode :: FlatMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let flat_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let flat_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , flat_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # flat_map_ident = # input_ident -> flat_map (# f) ; }) ; (flat_map_ident , input_location_id) } HfPlusNode :: Filter { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_ident = # input_ident -> filter (# f) ; }) ; (filter_ident , input_location_id) } HfPlusNode :: FilterMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_map_ident = # input_ident -> filter_map (# f) ; }) ; (filter_map_ident , input_location_id) } HfPlusNode :: Sort (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sort_id = * next_stmt_id ; * next_stmt_id += 1 ; let sort_ident = syn :: Ident :: new (& format ! ("stream_{}" , sort_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # sort_ident = # input_ident -> sort () ; }) ; (sort_ident , input_location_id) } HfPlusNode :: DeferTick (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let defer_tick_id = * next_stmt_id ; * next_stmt_id += 1 ; let defer_tick_ident = syn :: Ident :: new (& format ! ("stream_{}" , defer_tick_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # defer_tick_ident = # input_ident -> defer_tick_lazy () ; }) ; (defer_tick_ident , input_location_id) } HfPlusNode :: Enumerate (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let enumerate_id = * next_stmt_id ; * next_stmt_id += 1 ; let enumerate_ident = syn :: Ident :: new (& format ! ("stream_{}" , enumerate_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # enumerate_ident = # input_ident -> enumerate () ; }) ; (enumerate_ident , input_location_id) } HfPlusNode :: Inspect { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let inspect_id = * next_stmt_id ; * next_stmt_id += 1 ; let inspect_ident = syn :: Ident :: new (& format ! ("stream_{}" , inspect_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # inspect_ident = # input_ident -> inspect (# f) ; }) ; (inspect_ident , input_location_id) } HfPlusNode :: Unique (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let unique_id = * next_stmt_id ; * next_stmt_id += 1 ; let unique_ident = syn :: Ident :: new (& format ! ("stream_{}" , unique_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # unique_ident = # input_ident -> unique ::<'tick > () ; }) ; (unique_ident , input_location_id) } HfPlusNode :: Fold { .. } | HfPlusNode :: FoldKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Fold { .. }) { parse_quote ! (fold) } else { parse_quote ! (fold_keyed) } ; let (HfPlusNode :: Fold { init , acc , input } | HfPlusNode :: FoldKeyed { init , acc , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let fold_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'static > (# init , # acc) ; }) ; } else { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'tick > (# init , # acc) ; }) ; } (fold_ident , input_location_id) } HfPlusNode :: Reduce { .. } | HfPlusNode :: ReduceKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Reduce { .. }) { parse_quote ! (reduce) } else { parse_quote ! (reduce_keyed) } ; let (HfPlusNode :: Reduce { f , input } | HfPlusNode :: ReduceKeyed { f , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let reduce_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'static > (# f) ; }) ; } else { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'tick > (# f) ; }) ; } (reduce_ident , input_location_id) } HfPlusNode :: Network { from_location : _ , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input , } => { let (sink_expr , source_expr , _connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { panic ! ("Expected the network to be finalized") } DebugInstantiate :: Finalized (sink , source , connect_fn) => { (sink , source , connect_fn) } } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sender_builder = graph_builders . entry (input_location_id) . or_default () ; if let Some (serialize_pipeline) = serialize_pipeline { sender_builder . add_statement (parse_quote ! { # input_ident -> # serialize_pipeline -> dest_sink (# sink_expr) ; }) ; } else { sender_builder . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink_expr) ; }) ; } let to_id = match to_location { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let receiver_builder = graph_builders . entry (* to_id) . or_default () ; let receiver_stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let receiver_stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , receiver_stream_id) , Span :: call_site ()) ; if let Some (deserialize_pipeline) = deserialize_pipeline { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) -> # deserialize_pipeline ; }) ; } else { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) ; }) ; } (receiver_stream_ident , * to_id) } } } } } pub mod persist_pullup { pub use std :: cell :: RefCell ; pub use std :: collections :: HashSet ; pub use std :: ops :: Deref ; pub use crate :: ir :: * ; pub fn persist_pullup_node < 'a > (node : & mut HfPlusNode < 'a > , seen_tees : & mut SeenTees < 'a > , persist_pulled_tees : & mut HashSet < * const RefCell < HfPlusNode < 'a > > > ,) { node . transform_children (| n , s | persist_pullup_node (n , s , persist_pulled_tees) , seen_tees ,) ; match node { HfPlusNode :: Unpersist (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Unpersist (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Delta (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Delta (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Tee { inner } => { if persist_pulled_tees . contains (& (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >)) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } else { let inner_borrow = inner . borrow () ; if let HfPlusNode :: Persist (_) = inner_borrow . deref () { drop (inner_borrow) ; persist_pulled_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >) ; if let HfPlusNode :: Persist (box behind_persist) = inner . replace (HfPlusNode :: Placeholder) { * inner . borrow_mut () = behind_persist ; } else { unreachable ! () } * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } } } HfPlusNode :: Map { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Map { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Map { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: FlatMap { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: FlatMap { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: FlatMap { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Filter { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Filter { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Filter { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Network { input : box HfPlusNode :: Persist (_) , .. } => { if let HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Union (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Union (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Union (left , right))) ; } else { unreachable ! () } } HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: CrossProduct (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,) ,)))) ; } else { unreachable ! () } } HfPlusNode :: Join (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Join (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: Join (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,))))) ; } else { unreachable ! () } } _ => { } } } pub fn persist_pullup (ir : Vec < HfPlusLeaf >) -> Vec < HfPlusLeaf > { let mut seen_tees = Default :: default () ; let mut persist_pulled_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| n , s | persist_pullup_node (n , s , & mut persist_pulled_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn persist_pullup_through_map () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } # [test] fn persist_pullup_behind_tee () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; let before_tee = flow . source_iter (& process , q ! (0 .. 10)) . tick_batch () . persist () ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } } } pub mod profiler { pub use std :: cell :: RefCell ; pub use hydroflow :: futures :: channel :: mpsc :: UnboundedSender ; pub use stageleft :: * ; pub use crate as hydroflow_plus ; pub use crate :: ir :: * ; pub use crate :: RuntimeContext ; pub fn increment_counter (count : & mut u64) { * count += 1 ; } pub fn quoted_any_fn < 'a , F : Fn (& usize) + 'a , Q : IntoQuotedMut < 'a , F > > (q : Q) -> Q { q } # [doc = " Add a profiling node before each node to count the cardinality of its input"] pub fn add_profiling_node < 'a > (node : & mut HfPlusNode < 'a > , _context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > , id : & mut u32 , seen_tees : & mut SeenTees < 'a > ,) { let my_id = * id ; * id += 1 ; node . transform_children (| node , seen_tees | { add_profiling_node (node , _context , counters , counter_queue , id , seen_tees) } , seen_tees ,) ; let orig_node = std :: mem :: replace (node , HfPlusNode :: Placeholder) ; * node = HfPlusNode :: Inspect { f : quoted_any_fn (q ! ({ counter_queue . borrow () . unbounded_send ((my_id as usize , counters . borrow () [my_id as usize])) . unwrap () ; counters . borrow_mut () [my_id as usize] = 0 ; move | _ | { hydroflow_plus :: profiler :: increment_counter (& mut counters . borrow_mut () [my_id as usize] ,) ; } })) . splice () . into () , input : Box :: new (orig_node) , } } # [doc = " Count the cardinality of each input and periodically output to a file"] pub fn profiling < 'a > (ir : Vec < HfPlusLeaf < 'a > > , context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > ,) -> Vec < HfPlusLeaf < 'a > > { let mut id = 0 ; let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | { add_profiling_node (node , context , counters , counter_queue , & mut id , seen_tees) } , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn profiler_wrapping_all_operators () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let runtime_context = flow . runtime_context () ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (& built . ir ()) ; let counters = RuntimeData :: new ("Fake") ; let counter_queue = RuntimeData :: new ("Fake") ; let pushed_down = built . with_default_optimize () . optimize_with (| ir | super :: profiling (ir , runtime_context , counters , counter_queue)) ; insta :: assert_debug_snapshot ! (& pushed_down . ir ()) ; let _ = pushed_down . compile_no_network :: < MultiGraph > () ; } } } pub mod properties { pub use std :: collections :: HashSet ; pub use stageleft :: * ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , SeenTees } ; pub use crate :: properties :: PropertyDatabase ; # [doc = " Allows us to convert the hydroflow datatype for folds to a binary operation for the algebra"] # [doc = " property tests."] # [allow (dead_code)] pub fn convert_hf_to_binary < I , A : Default , F : Fn (& mut A , I) > (f : F) -> impl Fn (I , I) -> A { move | a , b | { let mut acc = Default :: default () ; f (& mut acc , a) ; f (& mut acc , b) ; acc } } # [cfg (stageleft_macro)] impl PropertyDatabase { # [doc = " Tags the expression as commutative."] pub fn add_commutative_tag < 'a , I , A , F : Fn (& mut A , I) , Q : Quoted < 'a , F > + Clone > (& mut self , expr : Q ,) -> Q { let expr_clone = expr . clone () ; self . commutative . insert (expr_clone . splice ()) ; expr } pub fn is_tagged_commutative (& self , expr : & syn :: Expr) -> bool { self . commutative . contains (expr) } } pub fn properties_optimize_node < 'a > (node : & mut HfPlusNode < 'a > , db : & PropertyDatabase , seen_tees : & mut SeenTees < 'a > ,) { node . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , seen_tees ,) ; match node { HfPlusNode :: ReduceKeyed { f , .. } if db . is_tagged_commutative (& f . 0) => { dbg ! ("IDENTIFIED COMMUTATIVE OPTIMIZATION for {:?}" , & f) ; } _ => { } } } pub fn properties_optimize < 'a > (ir : Vec < HfPlusLeaf < 'a > > , db : & PropertyDatabase ,) -> Vec < HfPlusLeaf < 'a > > { let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use super :: * ; use crate :: deploy :: SingleProcessGraph ; use crate :: FlowBuilder ; # [test] fn test_property_database () { let mut db = PropertyDatabase :: default () ; assert ! (! db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; let _ = db . add_commutative_tag (q ! (| a : & mut i32 , b : i32 | * a += b)) ; assert ! (db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; } # [test] fn test_property_optimized () { let flow = FlowBuilder :: new () ; let mut database = PropertyDatabase :: default () ; let process = flow . process :: < () > () ; let counter_func = q ! (| count : & mut i32 , _ | * count += 1) ; let _ = database . add_commutative_tag (counter_func) ; flow . source_iter (& process , q ! (vec ! [])) . map (q ! (| string : String | (string , ()))) . tick_batch () . fold_keyed (q ! (|| 0) , counter_func) . all_ticks () . for_each (q ! (| (string , count) | println ! ("{}: {}" , string , count))) ; let built = flow . finalize () . optimize_with (| ir | properties_optimize (ir , & database)) . with_default_optimize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let _ = built . compile_no_network :: < SingleProcessGraph > () ; } } } pub use crate :: RuntimeContext ; # [cfg (stageleft_macro)] impl Copy for RuntimeContext < '_ > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Context > for RuntimeContext < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (quote ! (& context))) } } pub use crate :: HfCompiled ; # [cfg (stageleft_macro)] impl < 'a , ID > HfCompiled < 'a , ID > { pub fn hydroflow_ir (& self) -> & BTreeMap < usize , HydroflowGraph > { & self . hydroflow_ir } } # [cfg (stageleft_macro)] impl < 'a > HfCompiled < 'a , usize > { pub fn with_dynamic_id (self , id : impl Quoted < 'a , usize >) -> HfBuiltWithId < 'a > { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; let mut conditioned_tokens = None ; for (subgraph_id , flat_graph) in self . hydroflow_ir { let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; let my_extra_stmts = self . extra_stmts . get (& subgraph_id) . cloned () . unwrap_or_default () ; if let Some (conditioned_tokens) = conditioned_tokens . as_mut () { * conditioned_tokens = syn :: parse_quote ! { # conditioned_tokens else if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } } ; } else { conditioned_tokens = Some (syn :: parse_quote ! { if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } }) ; } } let conditioned_tokens : TokenStream = conditioned_tokens . unwrap () ; let id = id . splice () ; HfBuiltWithId { tokens : syn :: parse_quote ! ({ let __given_id = # id ; # conditioned_tokens else { panic ! ("Invalid node id: {}" , __given_id) ; } }) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfCompiled < 'a , () > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfCompiled < 'a , () > { fn to_tokens (mut self) -> (Option < TokenStream > , Option < TokenStream >) { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; if self . hydroflow_ir . len () != 1 { panic ! ("Expected exactly one subgraph in the Hydroflow IR") ; } let flat_graph = self . hydroflow_ir . remove (& 0) . unwrap () ; let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; (None , Some (tokens)) } } pub use crate :: HfBuiltWithId ; # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfBuiltWithId < 'a > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfBuiltWithId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (self . tokens)) } }
[INFO] [stdout] 1 + pub use std :: collections :: BTreeMap ; pub use std :: marker :: PhantomData ; pub use hydroflow :: scheduled :: context :: Context ; pub use hydroflow :: scheduled :: graph :: Hydroflow ; pub use hydroflow :: * ; pub use lang :: graph :: { partition_graph , HydroflowGraph } ; pub use proc_macro2 :: TokenStream ; pub use quote :: quote ; pub use stageleft :: runtime_support :: FreeVariable ; pub use stageleft :: Quoted ; pub mod runtime_support { pub use bincode ; } pub mod stream { pub use std :: cell :: RefCell ; pub use std :: hash :: Hash ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow :: bytes :: Bytes ; pub use hydroflow :: futures :: Sink ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: quote ; pub use serde :: de :: DeserializeOwned ; pub use serde :: Serialize ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use syn :: parse_quote ; pub use crate :: builder :: { ClusterIds , FlowLeaves } ; pub use crate :: cycle :: { CycleCollection , CycleComplete } ; pub use crate :: ir :: { DebugInstantiate , HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { CanSend , Location , LocationId } ; pub use crate :: { Cluster , Optional , Singleton } ; pub use crate :: stream :: Unbounded ; pub use crate :: stream :: Bounded ; pub use crate :: stream :: NoTick ; pub use crate :: stream :: Tick ; pub use crate :: stream :: Stream ; # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Stream { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Stream < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Stream { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , C , N > > ,) -> Stream < 'a , (T , O) , W , C , N > where O : Clone , { let other : Optional < 'a , O , Bounded , C , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn cross_product < O > (self , other : Stream < 'a , O , W , C , N >) -> Stream < 'a , (T , O) , W , C , N > where T : Clone , O : Clone , { if self . location_kind != other . location_kind { panic ! ("cross_product must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossProduct (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn union (self , other : Stream < 'a , T , W , C , N >) -> Stream < 'a , T , W , C , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn dest_sink < S : Unpin + Sink < T > + 'a > (self , sink : impl Quoted < 'a , S >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: DestSink { sink : sink . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn first (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } # [doc = " Allow this stream through if the other stream has elements, otherwise the output is empty."] pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } # [doc = " Allow this stream through if the other stream is empty, otherwise the output is empty."] pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn enumerate (self) -> Stream < 'a , (usize , T) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Enumerate (Box :: new (self . ir_node . into_inner ())) ,) } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn sort (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Ord , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Sort (Box :: new (self . ir_node . into_inner ())) ,) } pub fn count (self) -> Singleton < 'a , usize , Bounded , Tick , N > { self . fold (q ! (|| 0usize) , q ! (| count , _ | * count += 1)) } pub fn delta (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } pub fn unique (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Eq + Hash , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unique (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn tick_batch (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_prefix (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { self . tick_batch () . persist () } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn for_each < F : Fn (T) + 'a > (self , f : impl IntoQuotedMut < 'a , F >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: ForEach { input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , f : f . splice () . into () , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Unbounded , NoTick , N > { pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . tick_batch () . continue_if (samples . first ()) . all_ticks () } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Unbounded , NoTick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , C , N : Location > Stream < 'a , T , Bounded , C , N > { pub fn filter_not_in (self , other : Stream < 'a , T , Bounded , C , N >) -> Stream < 'a , T , Bounded , C , N > where T : Eq + Hash , { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Difference (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Stream < 'a , & T , W , C , N > { pub fn cloned (self) -> Stream < 'a , T , W , C , N > { self . map (q ! (| d | d . clone ())) } } # [cfg (stageleft_macro)] impl < 'a , K , V1 , W , C , N : Location > Stream < 'a , (K , V1) , W , C , N > { pub fn join < W2 , V2 > (self , n : Stream < 'a , (K , V2) , W2 , C , N > ,) -> Stream < 'a , (K , (V1 , V2)) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Join (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } pub fn anti_join < W2 > (self , n : Stream < 'a , K , W2 , C , N >) -> Stream < 'a , (K , V1) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("anti_join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: AntiJoin (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , K : Eq + Hash , V , N : Location > Stream < 'a , (K , V) , Bounded , Tick , N > { pub fn fold_keyed < A , I : Fn () -> A + 'a , F : Fn (& mut A , V) + 'a > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , A) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FoldKeyed { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce_keyed < F : Fn (& mut V , V) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , V) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: ReduceKeyed { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } pub fn get_this_crate () -> TokenStream { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , Span :: call_site ()) ; quote ! { # ident } } } } pub fn serialize_bincode < T : Serialize > (is_demux : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if is_demux { parse_quote ! { map (| (id , data) | { (id , # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into ()) }) } } else { parse_quote ! { map (| data | { # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into () }) } } } pub fn deserialize_bincode < T : DeserializeOwned > (tagged : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if tagged { parse_quote ! { map (| res | { let (id , b) = res . unwrap () ; (id , # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& b) . unwrap ()) }) } } else { parse_quote ! { map (| res | { # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& res . unwrap ()) . unwrap () }) } } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn send_bincode < N2 : Location , CoreType > (self , other : & N2 ,) -> Stream < 'a , N :: Out < CoreType > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T > , CoreType : Serialize + DeserializeOwned , { let serialize_pipeline = Some (serialize_bincode :: < CoreType > (N :: is_demux ())) ; let deserialize_pipeline = Some (deserialize_bincode :: < CoreType > (N :: is_tagged ())) ; Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bytes < N2 : Location > (self , other : & N2 ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T > , { Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline : None , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline : if N :: is_tagged () { Some (parse_quote ! (map (| (id , b) | (id , b . unwrap () . freeze ())))) } else { Some (parse_quote ! (map (| b | b . unwrap () . freeze ()))) } , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bincode_interleaved < N2 : Location , Tag , CoreType > (self , other : & N2 ,) -> Stream < 'a , CoreType , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T , Out < CoreType > = (Tag , CoreType) > , CoreType : Serialize + DeserializeOwned , { self . send_bincode :: < N2 , CoreType > (other) . map (q ! (| (_ , b) | b)) } pub fn send_bytes_interleaved < N2 : Location , Tag > (self , other : & N2 ,) -> Stream < 'a , Bytes , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T , Out < Bytes > = (Tag , Bytes) > , { self . send_bytes :: < N2 > (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bincode < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < T > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) > , T : Clone + Serialize + DeserializeOwned , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bincode (other) } pub fn broadcast_bincode_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , T , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) , Out < T > = (Tag , T) > + 'a , T : Clone + Serialize + DeserializeOwned , { self . broadcast_bincode (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bytes < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) > + 'a , T : Clone , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bytes (other) } pub fn broadcast_bytes_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , Bytes , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) , Out < Bytes > = (Tag , Bytes) > + 'a , T : Clone , { self . broadcast_bytes (other) . map (q ! (| (_ , b) | b)) } } } pub use stream :: { Bounded , NoTick , Stream , Tick , Unbounded } ; pub mod singleton { pub use std :: cell :: RefCell ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use crate :: builder :: FlowLeaves ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial , CycleComplete } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: Stream ; pub use crate :: singleton :: CrossResult ; # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Singleton < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Singleton :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } pub use crate :: singleton :: Singleton ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Singleton { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleComplete < 'a > for Singleton < 'a , T , Bounded , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleCollectionWithInitial < 'a > for Singleton < 'a , T , Bounded , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , initial : Self , l : LocationId ,) -> Self { Singleton :: new (l , ir_leaves , HfPlusNode :: Union (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , }) , initial . ir_node . into_inner () . into () ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Singleton < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Singleton { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , U , W , C , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (Self :: other_ir_node (other)) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Singleton < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CrossSingleton (Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , Box :: new (HfPlusNode :: Unpersist (Box :: new (Self :: other_ir_node (other)))) ,))) ,) } } pub use crate :: singleton :: Optional ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Optional { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } pub fn some (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: new (singleton . location_kind , singleton . ir_leaves , singleton . ir_node . into_inner () ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > From < Singleton < 'a , T , W , C , N > > for Optional < 'a , T , W , C , N > { fn from (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: some (singleton) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Optional < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Optional { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn into_stream (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , Tick , N > > ,) -> Optional < 'a , (T , O) , Bounded , Tick , N > where O : Clone , { let other : Optional < 'a , O , Bounded , Tick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn union (self , other : Optional < 'a , T , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Optional < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_samples (self) -> Stream < 'a , T , Unbounded , NoTick , N > { self . latest_tick () . all_ticks () } pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . latest_tick () . continue_if (samples . first ()) . latest () . tick_samples () } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Unbounded , NoTick , N > > ,) -> Optional < 'a , (T , O) , Unbounded , NoTick , N > where O : Clone , { let other : Optional < 'a , O , Unbounded , NoTick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } self . latest_tick () . cross_singleton (other . latest_tick ()) . latest () } } } pub use singleton :: { Optional , Singleton } ; pub mod location { pub use std :: marker :: PhantomData ; pub use crate :: location :: LocationId ; pub use crate :: location :: Location ; pub use crate :: location :: Process ; # [cfg (stageleft_macro)] impl < P > Clone for Process < P > { fn clone (& self) -> Self { Process { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < P > Location for Process < P > { fn id (& self) -> LocationId { LocationId :: Process (self . id) } } pub use crate :: location :: Cluster ; # [cfg (stageleft_macro)] impl < C > Clone for Cluster < C > { fn clone (& self) -> Self { Cluster { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < C > Location for Cluster < C > { fn id (& self) -> LocationId { LocationId :: Cluster (self . id) } } pub use crate :: location :: CanSend ; # [cfg (stageleft_macro)] impl < P1 , P2 > CanSend < Process < P2 > > for Process < P1 > { type In < T > = T ; type Out < T > = T ; fn is_demux () -> bool { false } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < P1 , C2 > CanSend < Cluster < C2 > > for Process < P1 > { type In < T > = (u32 , T) ; type Out < T > = T ; fn is_demux () -> bool { true } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < C1 , P2 > CanSend < Process < P2 > > for Cluster < C1 > { type In < T > = T ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { false } fn is_tagged () -> bool { true } } # [cfg (stageleft_macro)] impl < C1 , C2 > CanSend < Cluster < C2 > > for Cluster < C1 > { type In < T > = (u32 , T) ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { true } fn is_tagged () -> bool { true } } } pub use location :: { Cluster , Process } ; pub mod deploy { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use stageleft :: Quoted ; pub mod graphs { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use super :: { LocalDeploy , Node , ProcessSpec } ; pub use crate :: deploy :: graphs :: SingleProcessGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for SingleProcessGraph { type Process = SingleNode ; type Cluster = SingleNode ; type Meta = () ; type GraphId = () ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { SingleNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { SingleNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , SingleProcessGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> SingleNode { SingleNode { } } } pub use crate :: deploy :: graphs :: SingleNode ; # [cfg (stageleft_macro)] impl Node for SingleNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } pub use crate :: deploy :: graphs :: MultiGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for MultiGraph { type Process = MultiNode ; type Cluster = MultiNode ; type Meta = () ; type GraphId = usize ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { MultiNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { MultiNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , MultiGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> MultiNode { MultiNode { } } } pub use crate :: deploy :: graphs :: MultiNode ; # [cfg (stageleft_macro)] impl Node for MultiNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } } pub use graphs :: * ; pub use crate :: deploy :: LocalDeploy ; pub use crate :: deploy :: Deploy ; # [cfg (stageleft_macro)] impl < 'a , T : Deploy < 'a , Process = N , Cluster = C , Meta = M , GraphId = R > , N : Node < Meta = M > , C : Node < Meta = M > , M : Default , R , > LocalDeploy < 'a > for T { type Process = N ; type Cluster = C ; type Meta = M ; type GraphId = R ; fn has_trivial_node () -> bool { < T as Deploy < 'a > > :: has_trivial_node () } fn trivial_process (id : usize) -> Self :: Process { < T as Deploy < 'a > > :: trivial_process (id) } fn trivial_cluster (id : usize) -> Self :: Cluster { < T as Deploy < 'a > > :: trivail_cluster (id) } } pub use crate :: deploy :: ProcessSpec ; pub use crate :: deploy :: ClusterSpec ; pub use crate :: deploy :: Node ; } pub use deploy :: { ClusterSpec , Deploy , ProcessSpec } ; pub mod cycle { pub use std :: marker :: PhantomData ; pub use crate :: builder :: FlowLeaves ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: cycle :: CycleComplete ; pub use crate :: cycle :: CycleCollection ; pub use crate :: cycle :: CycleCollectionWithInitial ; pub use crate :: cycle :: HfCycle ; # [cfg (stageleft_macro)] impl < 'a , S : CycleComplete < 'a > > HfCycle < 'a , S > { pub fn complete (self , stream : S) { let ident = self . ident ; S :: complete (stream , ident) } } } pub use cycle :: HfCycle ; pub mod builder { pub use std :: cell :: RefCell ; pub use std :: collections :: HashMap ; pub use std :: marker :: PhantomData ; pub use std :: rc :: Rc ; pub use std :: time :: Duration ; pub use hydroflow :: futures :: stream :: Stream as FuturesStream ; pub use hydroflow :: { tokio , tokio_stream } ; pub use internal :: TokenStream ; pub use proc_macro2 :: Span ; pub use quote :: quote ; pub use runtime_support :: FreeVariable ; pub use stageleft :: * ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Cluster , Location , LocationId , Process } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: { HfCycle , Optional , RuntimeContext , Singleton , Stream } ; pub mod built { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use hydroflow_lang :: graph :: { eliminate_extra_unions_tees , HydroflowGraph } ; pub use super :: deploy :: { DeployFlow , DeployResult } ; pub use crate :: deploy :: { ClusterSpec , Deploy , LocalDeploy , ProcessSpec } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Cluster , Process } ; pub use crate :: HfCompiled ; pub use crate :: builder :: built :: BuiltFlow ; # [cfg (stageleft_macro)] impl < 'a > Drop for BuiltFlow < 'a > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped BuiltFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn ir (& self) -> & Vec < HfPlusLeaf < 'a > > { & self . ir } pub fn optimize_with (mut self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> BuiltFlow < 'a > { self . used = true ; BuiltFlow { ir : f (std :: mem :: take (& mut self . ir)) , processes : std :: mem :: take (& mut self . processes) , clusters : std :: mem :: take (& mut self . clusters) , used : false , _phantom : PhantomData , } } } pub fn build_inner (ir : & mut Vec < HfPlusLeaf >) -> BTreeMap < usize , HydroflowGraph > { let mut builders = BTreeMap :: new () ; let mut built_tees = HashMap :: new () ; let mut next_stmt_id = 0 ; for leaf in ir { leaf . emit (& mut builders , & mut built_tees , & mut next_stmt_id) ; } builders . into_iter () . map (| (k , v) | { let (mut flat_graph , _ , _) = v . build () ; eliminate_extra_unions_tees (& mut flat_graph) ; (k , flat_graph) }) . collect () } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn compile_no_network < D : LocalDeploy < 'a > > (mut self) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; HfCompiled { hydroflow_ir : build_inner (& mut self . ir) , extra_stmts : BTreeMap :: new () , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> BuiltFlow < 'a > { self . optimize_with (crate :: persist_pullup :: persist_pullup) } fn into_deploy < D : LocalDeploy < 'a > > (mut self) -> DeployFlow < 'a , D > { self . used = true ; let processes = if D :: has_trivial_node () { self . processes . iter () . map (| id | (* id , D :: trivial_process (* id))) . collect () } else { HashMap :: new () } ; let clusters = if D :: has_trivial_node () { self . clusters . iter () . map (| id | (* id , D :: trivial_cluster (* id))) . collect () } else { HashMap :: new () } ; DeployFlow { ir : std :: mem :: take (& mut self . ir) , nodes : processes , clusters , used : false , _phantom : PhantomData , } } pub fn with_process < P , D : LocalDeploy < 'a > > (self , process : & Process < P > , spec : impl ProcessSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_process (process , spec) } pub fn with_cluster < C , D : LocalDeploy < 'a > > (self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_cluster (cluster , spec) } pub fn compile < D : Deploy < 'a > + 'a > (self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . into_deploy :: < D > () . compile (env) } pub fn deploy < D : Deploy < 'a , CompileEnv = () > + 'a > (self , env : & mut D :: InstantiateEnv ,) -> DeployResult < 'a , D > { self . into_deploy :: < D > () . deploy (env) } } } pub mod deploy { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use proc_macro2 :: Span ; pub use stageleft :: Quoted ; pub use super :: built :: build_inner ; pub use crate :: deploy :: { LocalDeploy , Node } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: { Cluster , ClusterSpec , Deploy , HfCompiled , Process , ProcessSpec } ; pub use crate :: builder :: deploy :: DeployFlow ; # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > Drop for DeployFlow < 'a , D > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped DeployFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > DeployFlow < 'a , D > { pub fn with_process < P > (mut self , process : & Process < P > , spec : impl ProcessSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < P > () . to_string () ; self . nodes . insert (process . id , spec . build (process . id , & tag_name)) ; self } pub fn with_cluster < C > (mut self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < C > () . to_string () ; self . clusters . insert (cluster . id , spec . build (cluster . id , & tag_name)) ; self } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployFlow < 'a , D > { pub fn compile (mut self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; let mut seen_tees : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | leaf . compile_network :: < D > (env , & mut seen_tees , & self . nodes , & self . clusters)) . collect () ; let extra_stmts = self . extra_stmts (env) ; HfCompiled { hydroflow_ir : build_inner (& mut ir_leaves_networked) , extra_stmts , _phantom : PhantomData , } } fn extra_stmts (& self , env : & < D as Deploy < 'a > > :: CompileEnv) -> BTreeMap < usize , Vec < syn :: Stmt > > { let all_locations_count = self . nodes . len () + self . clusters . len () ; let mut extra_stmts : BTreeMap < usize , Vec < syn :: Stmt > > = BTreeMap :: new () ; for & c_id in self . clusters . keys () { let self_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , c_id) , Span :: call_site () ,) ; let self_id_expr = D :: cluster_self_id (env) . splice () ; extra_stmts . entry (c_id) . or_default () . push (syn :: parse_quote ! { let # self_id_ident = # self_id_expr ; }) ; for other_location in 0 .. all_locations_count { let other_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , c_id) , Span :: call_site () ,) ; let other_id_expr = D :: cluster_ids (env , c_id) . splice () ; extra_stmts . entry (other_location) . or_default () . push (syn :: parse_quote ! { let # other_id_ident = # other_id_expr ; }) ; } } extra_stmts } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a , CompileEnv = () > > DeployFlow < 'a , D > { # [must_use] pub fn deploy (mut self , env : & mut D :: InstantiateEnv) -> DeployResult < 'a , D > { self . used = true ; let mut seen_tees_instantiate : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | { leaf . compile_network :: < D > (& () , & mut seen_tees_instantiate , & self . nodes , & self . clusters ,) }) . collect () ; let mut compiled = build_inner (& mut ir_leaves_networked) ; let mut extra_stmts = self . extra_stmts (& ()) ; let mut meta = D :: Meta :: default () ; let (mut processes , mut clusters) = (std :: mem :: take (& mut self . nodes) . into_iter () . map (| (node_id , node) | { node . instantiate (env , & mut meta , compiled . remove (& node_id) . unwrap () , extra_stmts . remove (& node_id) . unwrap_or_default () ,) ; (node_id , node) }) . collect :: < HashMap < _ , _ > > () , std :: mem :: take (& mut self . clusters) . into_iter () . map (| (cluster_id , cluster) | { cluster . instantiate (env , & mut meta , compiled . remove (& cluster_id) . unwrap () , extra_stmts . remove (& cluster_id) . unwrap_or_default () ,) ; (cluster_id , cluster) }) . collect :: < HashMap < _ , _ > > () ,) ; for node in processes . values_mut () { node . update_meta (& meta) ; } for cluster in clusters . values_mut () { cluster . update_meta (& meta) ; } let mut seen_tees_connect = HashMap :: new () ; for leaf in ir_leaves_networked { leaf . connect_network (& mut seen_tees_connect) ; } DeployResult { processes , clusters , } } } pub use crate :: builder :: deploy :: DeployResult ; # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployResult < 'a , D > { pub fn get_process < P > (& self , p : & Process < P >) -> & D :: Process { let id = match p . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . processes . get (& id) . unwrap () } pub fn get_cluster < C > (& self , c : & Cluster < C >) -> & D :: Cluster { let id = match c . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . clusters . get (& id) . unwrap () } } } # [doc = " Tracks the leaves of the dataflow IR. This is referenced by"] # [doc = " `Stream` and `HfCycle` to build the IR. The inner option will"] # [doc = " be set to `None` when this builder is finalized."] pub type FlowLeaves < 'a > = Rc < RefCell < Option < Vec < HfPlusLeaf < 'a > > > > > ; pub use crate :: builder :: ClusterIds ; # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Vec < u32 > > for ClusterIds < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , & 'a Vec < u32 > > for ClusterIds < 'a > { } # [derive (Copy , Clone)] pub struct ClusterSelfId < 'a > { pub id : usize , pub _phantom : PhantomData < & 'a mut & 'a u32 > , } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < u32 > for ClusterSelfId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , u32 > for ClusterSelfId < 'a > { } pub use crate :: builder :: FlowBuilder ; # [cfg (stageleft_macro)] impl < 'a > Drop for FlowBuilder < 'a > { fn drop (& mut self) { if ! self . finalized { panic ! ("Dropped FlowBuilder without finalizing, you may have forgotten to call `with_default_optimize`, `optimize_with`, or `finalize`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > QuotedContext for FlowBuilder < 'a > { fn create () -> Self { FlowBuilder :: new () } } # [cfg (stageleft_macro)] impl < 'a > FlowBuilder < 'a > { # [allow (clippy :: new_without_default)] pub fn new () -> FlowBuilder < 'a > { FlowBuilder { ir_leaves : Rc :: new (RefCell :: new (Some (Vec :: new ()))) , nodes : RefCell :: new (vec ! []) , clusters : RefCell :: new (vec ! []) , cycle_ids : RefCell :: new (HashMap :: new ()) , next_node_id : RefCell :: new (0) , finalized : false , _phantom : PhantomData , } } pub fn finalize (mut self) -> built :: BuiltFlow < 'a > { self . finalized = true ; built :: BuiltFlow { ir : self . ir_leaves . borrow_mut () . take () . unwrap () , processes : self . nodes . replace (vec ! []) , clusters : self . clusters . replace (vec ! []) , used : false , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> built :: BuiltFlow < 'a > { self . finalize () . with_default_optimize () } pub fn optimize_with (self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> built :: BuiltFlow < 'a > { self . finalize () . optimize_with (f) } pub fn ir_leaves (& self) -> & FlowLeaves < 'a > { & self . ir_leaves } pub fn process < P > (& self) -> Process < P > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . nodes . borrow_mut () . push (id) ; Process { id , _phantom : PhantomData , } } pub fn cluster < C > (& self) -> Cluster < C > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . clusters . borrow_mut () . push (id) ; Cluster { id , _phantom : PhantomData , } } pub fn runtime_context (& self) -> RuntimeContext < 'a > { RuntimeContext { _phantom : PhantomData , } } pub fn cluster_members < C > (& self , cluster : & Cluster < C > ,) -> impl Quoted < 'a , & 'a Vec < u32 > > + Copy + 'a { ClusterIds { id : cluster . id , _phantom : PhantomData , } } pub fn cluster_self_id < C > (& self , cluster : & Cluster < C >) -> impl Quoted < 'a , u32 > + Copy + 'a { ClusterSelfId { id : cluster . id , _phantom : PhantomData , } } pub fn spin < L : Location > (& self , on : & L) -> Stream < 'a , () , Unbounded , NoTick , L > { Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Spin () , location_kind : on . id () , })) ,) } pub fn spin_batch < L : Location > (& self , on : & L , batch_size : impl Quoted < 'a , usize > + Copy + 'a ,) -> Stream < 'a , () , Bounded , Tick , L > { self . spin (on) . flat_map (q ! (move | _ | 0 .. batch_size)) . map (q ! (| _ | ())) . tick_batch () } pub fn source_stream < T , E : FuturesStream < Item = T > + Unpin , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Unbounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Stream (e . into ()) , location_kind : on . id () , })) ,) } pub fn source_iter < T , E : IntoIterator < Item = T > , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Bounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , })) ,) } pub fn singleton < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Singleton < 'a , T , Bounded , NoTick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Singleton :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,)))) ,) } pub fn singleton_first_tick < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Optional < 'a , T , Bounded , Tick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,) } pub fn source_interval < L : Location > (& self , on : & L , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , () , Unbounded , NoTick , L > { let interval = interval . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : on . id () , })) ,) } pub fn source_interval_delayed < L : Location > (& self , on : & L , delay : impl Quoted < 'a , Duration > + Copy + 'a , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , tokio :: time :: Instant , Unbounded , NoTick , L > { self . source_stream (on , q ! (tokio_stream :: wrappers :: IntervalStream :: new (tokio :: time :: interval_at (tokio :: time :: Instant :: now () + delay , interval))) ,) . tick_batch () . first () . latest () } pub fn cycle < S : CycleCollection < 'a > > (& self , on : & S :: Location) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , on . id ()) ,) } pub fn cycle_with_initial < S : CycleCollectionWithInitial < 'a > > (& self , on : & S :: Location , initial : S ,) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , initial , on . id ()) ,) } } } pub use builder :: FlowBuilder ; pub mod ir { pub use core :: panic ; pub use std :: cell :: RefCell ; pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow_lang :: graph :: FlatGraphBuilder ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: ToTokens ; pub use syn :: parse_quote ; pub use crate :: deploy :: Deploy ; pub use crate :: location :: LocationId ; pub use crate :: ir :: DebugExpr ; # [cfg (stageleft_macro)] impl From < syn :: Expr > for DebugExpr { fn from (expr : syn :: Expr) -> DebugExpr { DebugExpr (expr) } } # [cfg (stageleft_macro)] impl Deref for DebugExpr { type Target = syn :: Expr ; fn deref (& self) -> & Self :: Target { & self . 0 } } # [cfg (stageleft_macro)] impl ToTokens for DebugExpr { fn to_tokens (& self , tokens : & mut TokenStream) { self . 0 . to_tokens (tokens) ; } } # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugExpr { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "{}" , self . 0 . to_token_stream ()) } } pub use crate :: ir :: DebugInstantiate ; # [cfg (stageleft_macro)] impl < 'a > std :: fmt :: Debug for DebugInstantiate < 'a > { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<network instantiate>") } } pub use crate :: ir :: DebugPipelineFn ; # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugPipelineFn { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<function>") } } pub use crate :: ir :: HfPlusSource ; pub use crate :: ir :: HfPlusLeaf ; # [cfg (stageleft_macro)] impl < 'a > HfPlusLeaf < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . compile_network :: < D > (compile_env , s , nodes , clusters) ; } , seen_tees ,) } pub fn connect_network (self , seen_tees : & mut SeenTees < 'a >) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . connect_network (s) ; } , seen_tees ,) } pub fn transform_children (self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) -> HfPlusLeaf < 'a > { match self { HfPlusLeaf :: ForEach { f , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: ForEach { f , input } } HfPlusLeaf :: DestSink { sink , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: DestSink { sink , input } } HfPlusLeaf :: CycleSink { ident , location_kind , mut input , } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: CycleSink { ident , location_kind , input , } } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) { match self { HfPlusLeaf :: ForEach { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> for_each (# f) ; }) ; } HfPlusLeaf :: DestSink { sink , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink) ; }) ; } HfPlusLeaf :: CycleSink { ident , location_kind , input , } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; assert_eq ! (input_location_id , * location_id , "cycle_sink location mismatch") ; graph_builders . entry (* location_id) . or_default () . add_statement (parse_quote ! { # ident = # input_ident ; }) ; } } } } pub use crate :: ir :: HfPlusNode ; pub type SeenTees < 'a > = HashMap < * const RefCell < HfPlusNode < 'a > > , Rc < RefCell < HfPlusNode < 'a > > > > ; # [cfg (stageleft_macro)] impl < 'a > HfPlusNode < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (& mut self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) { self . transform_children (| n , s | n . compile_network :: < D > (compile_env , s , nodes , clusters) , seen_tees ,) ; if let HfPlusNode :: Network { from_location , to_location , instantiate_fn , .. } = self { let (sink_expr , source_expr , connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { let ((sink , source) , connect_fn) = match (from_location , to_location) { (LocationId :: Process (from) , LocationId :: Process (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: o2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Process (from) , LocationId :: Cluster (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: o2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Process (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: m2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Cluster (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: m2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } } ; (sink , source , connect_fn) } DebugInstantiate :: Finalized (_ , _ , _) => panic ! ("network already finalized") , } ; * instantiate_fn = DebugInstantiate :: Finalized (sink_expr , source_expr , connect_fn) ; } } pub fn connect_network (& mut self , seen_tees : & mut SeenTees < 'a >) { self . transform_children (| n , s | n . connect_network (s) , seen_tees) ; if let HfPlusNode :: Network { instantiate_fn , .. } = self { match instantiate_fn { DebugInstantiate :: Building () => panic ! ("network not built") , DebugInstantiate :: Finalized (_ , _ , ref connect_fn) => { connect_fn () ; } } } } pub fn transform_children (& mut self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) { match self { HfPlusNode :: Placeholder => { panic ! () ; } HfPlusNode :: Source { .. } => { } HfPlusNode :: CycleSource { .. } => { } HfPlusNode :: Tee { inner } => { if let Some (transformed) = seen_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { * inner = transformed . clone () ; } else { let transformed_cell = Rc :: new (RefCell :: new (HfPlusNode :: Placeholder)) ; seen_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , transformed_cell . clone () ,) ; let mut orig = inner . replace (HfPlusNode :: Placeholder) ; transform (& mut orig , seen_tees) ; * transformed_cell . borrow_mut () = orig ; * inner = transformed_cell ; } } HfPlusNode :: Persist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Unpersist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Delta (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Union (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossProduct (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossSingleton (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Join (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Difference (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: AntiJoin (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Map { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FlatMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Filter { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FilterMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Sort (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: DeferTick (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Enumerate (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Inspect { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Unique (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Fold { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FoldKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Reduce { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: ReduceKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Network { input , .. } => { transform (input . as_mut () , seen_tees) ; } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) -> (syn :: Ident , usize) { match self { HfPlusNode :: Placeholder => { panic ! () } HfPlusNode :: Persist (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let persist_id = * next_stmt_id ; * next_stmt_id += 1 ; let persist_ident = syn :: Ident :: new (& format ! ("stream_{}" , persist_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # persist_ident = # inner_ident -> persist ::<'static > () ; }) ; (persist_ident , location) } HfPlusNode :: Unpersist (_) => { panic ! ("Unpersist is a marker node and should have been optimized away. This is likely a compiler bug.") } HfPlusNode :: Delta (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let delta_id = * next_stmt_id ; * next_stmt_id += 1 ; let delta_ident = syn :: Ident :: new (& format ! ("stream_{}" , delta_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # delta_ident = # inner_ident -> multiset_delta () ; }) ; (delta_ident , location) } HfPlusNode :: Source { source , location_kind , } => { let source_id = * next_stmt_id ; * next_stmt_id += 1 ; let source_ident = syn :: Ident :: new (& format ! ("stream_{}" , source_id) , Span :: call_site ()) ; let source_stmt = match source { HfPlusSource :: Stream (expr) => { parse_quote ! { # source_ident = source_stream (# expr) ; } } HfPlusSource :: Iter (expr) => { parse_quote ! { # source_ident = source_iter (# expr) ; } } HfPlusSource :: Interval (expr) => { parse_quote ! { # source_ident = source_interval (# expr) ; } } HfPlusSource :: Spin () => { parse_quote ! { # source_ident = spin () ; } } } ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; graph_builders . entry (* location_id) . or_default () . add_statement (source_stmt) ; (source_ident , * location_id) } HfPlusNode :: CycleSource { ident , location_kind , } => { let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; (ident . clone () , * location_id) } HfPlusNode :: Tee { inner } => { if let Some (ret) = built_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { ret . clone () } else { let (inner_ident , inner_location_id) = inner . borrow () . emit (graph_builders , built_tees , next_stmt_id) ; let tee_id = * next_stmt_id ; * next_stmt_id += 1 ; let tee_ident = syn :: Ident :: new (& format ! ("stream_{}" , tee_id) , Span :: call_site ()) ; let builder = graph_builders . entry (inner_location_id) . or_default () ; builder . add_statement (parse_quote ! { # tee_ident = # inner_ident -> tee () ; }) ; built_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , (tee_ident . clone () , inner_location_id) ,) ; (tee_ident , inner_location_id) } } HfPlusNode :: Union (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "union inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let union_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # union_ident = union () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [0] # union_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # union_ident ; }) ; (union_ident , left_location_id) } HfPlusNode :: CrossSingleton (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "cross_singleton inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let cross_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # cross_ident = cross_singleton () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [input] # cross_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [single] # cross_ident ; }) ; (cross_ident , left_location_id) } HfPlusNode :: CrossProduct (..) | HfPlusNode :: Join (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: CrossProduct (..)) { parse_quote ! (cross_join_multiset) } else { parse_quote ! (join_multiset) } ; let (HfPlusNode :: CrossProduct (left , right) | HfPlusNode :: Join (left , right)) = self else { unreachable ! () } ; let (left_inner , left_was_persist) = if let HfPlusNode :: Persist (left) = left . as_ref () { (left , true) } else { (left , false) } ; let (right_inner , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left_inner . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right_inner . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "join / cross product inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; match (left_was_persist , right_was_persist) { (true , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'static > () ; }) ; } (true , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'tick > () ; }) ; } (false , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } (false , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } } ; builder . add_statement (parse_quote ! { # left_ident -> [0] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Difference (..) | HfPlusNode :: AntiJoin (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Difference (..)) { parse_quote ! (difference_multiset) } else { parse_quote ! (anti_join_multiset) } ; let (HfPlusNode :: Difference (left , right) | HfPlusNode :: AntiJoin (left , right)) = self else { unreachable ! () } ; let (right , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "difference / anti join inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; if right_was_persist { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } else { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } builder . add_statement (parse_quote ! { # left_ident -> [pos] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [neg] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Map { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let map_id = * next_stmt_id ; * next_stmt_id += 1 ; let map_ident = syn :: Ident :: new (& format ! ("stream_{}" , map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # map_ident = # input_ident -> map (# f) ; }) ; (map_ident , input_location_id) } HfPlusNode :: FlatMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let flat_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let flat_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , flat_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # flat_map_ident = # input_ident -> flat_map (# f) ; }) ; (flat_map_ident , input_location_id) } HfPlusNode :: Filter { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_ident = # input_ident -> filter (# f) ; }) ; (filter_ident , input_location_id) } HfPlusNode :: FilterMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_map_ident = # input_ident -> filter_map (# f) ; }) ; (filter_map_ident , input_location_id) } HfPlusNode :: Sort (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sort_id = * next_stmt_id ; * next_stmt_id += 1 ; let sort_ident = syn :: Ident :: new (& format ! ("stream_{}" , sort_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # sort_ident = # input_ident -> sort () ; }) ; (sort_ident , input_location_id) } HfPlusNode :: DeferTick (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let defer_tick_id = * next_stmt_id ; * next_stmt_id += 1 ; let defer_tick_ident = syn :: Ident :: new (& format ! ("stream_{}" , defer_tick_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # defer_tick_ident = # input_ident -> defer_tick_lazy () ; }) ; (defer_tick_ident , input_location_id) } HfPlusNode :: Enumerate (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let enumerate_id = * next_stmt_id ; * next_stmt_id += 1 ; let enumerate_ident = syn :: Ident :: new (& format ! ("stream_{}" , enumerate_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # enumerate_ident = # input_ident -> enumerate () ; }) ; (enumerate_ident , input_location_id) } HfPlusNode :: Inspect { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let inspect_id = * next_stmt_id ; * next_stmt_id += 1 ; let inspect_ident = syn :: Ident :: new (& format ! ("stream_{}" , inspect_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # inspect_ident = # input_ident -> inspect (# f) ; }) ; (inspect_ident , input_location_id) } HfPlusNode :: Unique (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let unique_id = * next_stmt_id ; * next_stmt_id += 1 ; let unique_ident = syn :: Ident :: new (& format ! ("stream_{}" , unique_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # unique_ident = # input_ident -> unique ::<'tick > () ; }) ; (unique_ident , input_location_id) } HfPlusNode :: Fold { .. } | HfPlusNode :: FoldKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Fold { .. }) { parse_quote ! (fold) } else { parse_quote ! (fold_keyed) } ; let (HfPlusNode :: Fold { init , acc , input } | HfPlusNode :: FoldKeyed { init , acc , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let fold_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'static > (# init , # acc) ; }) ; } else { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'tick > (# init , # acc) ; }) ; } (fold_ident , input_location_id) } HfPlusNode :: Reduce { .. } | HfPlusNode :: ReduceKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Reduce { .. }) { parse_quote ! (reduce) } else { parse_quote ! (reduce_keyed) } ; let (HfPlusNode :: Reduce { f , input } | HfPlusNode :: ReduceKeyed { f , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let reduce_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'static > (# f) ; }) ; } else { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'tick > (# f) ; }) ; } (reduce_ident , input_location_id) } HfPlusNode :: Network { from_location : _ , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input , } => { let (sink_expr , source_expr , _connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { panic ! ("Expected the network to be finalized") } DebugInstantiate :: Finalized (sink , source , connect_fn) => { (sink , source , connect_fn) } } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sender_builder = graph_builders . entry (input_location_id) . or_default () ; if let Some (serialize_pipeline) = serialize_pipeline { sender_builder . add_statement (parse_quote ! { # input_ident -> # serialize_pipeline -> dest_sink (# sink_expr) ; }) ; } else { sender_builder . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink_expr) ; }) ; } let to_id = match to_location { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let receiver_builder = graph_builders . entry (* to_id) . or_default () ; let receiver_stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let receiver_stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , receiver_stream_id) , Span :: call_site ()) ; if let Some (deserialize_pipeline) = deserialize_pipeline { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) -> # deserialize_pipeline ; }) ; } else { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) ; }) ; } (receiver_stream_ident , * to_id) } } } } } pub mod persist_pullup { pub use std :: cell :: RefCell ; pub use std :: collections :: HashSet ; pub use std :: ops :: Deref ; pub use crate :: ir :: * ; pub fn persist_pullup_node < 'a > (node : & mut HfPlusNode < 'a > , seen_tees : & mut SeenTees < 'a > , persist_pulled_tees : & mut HashSet < * const RefCell < HfPlusNode < 'a > > > ,) { node . transform_children (| n , s | persist_pullup_node (n , s , persist_pulled_tees) , seen_tees ,) ; match node { HfPlusNode :: Unpersist (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Unpersist (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Delta (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Delta (box HfPlusNode :: Persist (behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Tee { inner } => { if persist_pulled_tees . contains (& (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >)) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } else { let inner_borrow = inner . borrow () ; if let HfPlusNode :: Persist (_) = inner_borrow . deref () { drop (inner_borrow) ; persist_pulled_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >) ; if let HfPlusNode :: Persist (box behind_persist) = inner . replace (HfPlusNode :: Placeholder) { * inner . borrow_mut () = behind_persist ; } else { unreachable ! () } * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } } } HfPlusNode :: Map { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Map { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Map { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: FlatMap { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: FlatMap { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: FlatMap { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Filter { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Filter { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Filter { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Network { input : box HfPlusNode :: Persist (_) , .. } => { if let HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Union (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Union (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Union (left , right))) ; } else { unreachable ! () } } HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: CrossProduct (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,) ,)))) ; } else { unreachable ! () } } HfPlusNode :: Join (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Join (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: Join (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,))))) ; } else { unreachable ! () } } _ => { } } } pub fn persist_pullup (ir : Vec < HfPlusLeaf >) -> Vec < HfPlusLeaf > { let mut seen_tees = Default :: default () ; let mut persist_pulled_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| n , s | persist_pullup_node (n , s , & mut persist_pulled_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn persist_pullup_through_map () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } # [test] fn persist_pullup_behind_tee () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; let before_tee = flow . source_iter (& process , q ! (0 .. 10)) . tick_batch () . persist () ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } } } pub mod profiler { pub use std :: cell :: RefCell ; pub use hydroflow :: futures :: channel :: mpsc :: UnboundedSender ; pub use stageleft :: * ; pub use crate as hydroflow_plus ; pub use crate :: ir :: * ; pub use crate :: RuntimeContext ; pub fn increment_counter (count : & mut u64) { * count += 1 ; } pub fn quoted_any_fn < 'a , F : Fn (& usize) + 'a , Q : IntoQuotedMut < 'a , F > > (q : Q) -> Q { q } # [doc = " Add a profiling node before each node to count the cardinality of its input"] pub fn add_profiling_node < 'a > (node : & mut HfPlusNode < 'a > , _context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > , id : & mut u32 , seen_tees : & mut SeenTees < 'a > ,) { let my_id = * id ; * id += 1 ; node . transform_children (| node , seen_tees | { add_profiling_node (node , _context , counters , counter_queue , id , seen_tees) } , seen_tees ,) ; let orig_node = std :: mem :: replace (node , HfPlusNode :: Placeholder) ; * node = HfPlusNode :: Inspect { f : quoted_any_fn (q ! ({ counter_queue . borrow () . unbounded_send ((my_id as usize , counters . borrow () [my_id as usize])) . unwrap () ; counters . borrow_mut () [my_id as usize] = 0 ; move | _ | { hydroflow_plus :: profiler :: increment_counter (& mut counters . borrow_mut () [my_id as usize] ,) ; } })) . splice () . into () , input : Box :: new (orig_node) , } } # [doc = " Count the cardinality of each input and periodically output to a file"] pub fn profiling < 'a > (ir : Vec < HfPlusLeaf < 'a > > , context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > ,) -> Vec < HfPlusLeaf < 'a > > { let mut id = 0 ; let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | { add_profiling_node (node , context , counters , counter_queue , & mut id , seen_tees) } , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn profiler_wrapping_all_operators () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let runtime_context = flow . runtime_context () ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (& built . ir ()) ; let counters = RuntimeData :: new ("Fake") ; let counter_queue = RuntimeData :: new ("Fake") ; let pushed_down = built . with_default_optimize () . optimize_with (| ir | super :: profiling (ir , runtime_context , counters , counter_queue)) ; insta :: assert_debug_snapshot ! (& pushed_down . ir ()) ; let _ = pushed_down . compile_no_network :: < MultiGraph > () ; } } } pub mod properties { pub use std :: collections :: HashSet ; pub use stageleft :: * ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , SeenTees } ; pub use crate :: properties :: PropertyDatabase ; # [doc = " Allows us to convert the hydroflow datatype for folds to a binary operation for the algebra"] # [doc = " property tests."] # [allow (dead_code)] pub fn convert_hf_to_binary < I , A : Default , F : Fn (& mut A , I) > (f : F) -> impl Fn (I , I) -> A { move | a , b | { let mut acc = Default :: default () ; f (& mut acc , a) ; f (& mut acc , b) ; acc } } # [cfg (stageleft_macro)] impl PropertyDatabase { # [doc = " Tags the expression as commutative."] pub fn add_commutative_tag < 'a , I , A , F : Fn (& mut A , I) , Q : Quoted < 'a , F > + Clone > (& mut self , expr : Q ,) -> Q { let expr_clone = expr . clone () ; self . commutative . insert (expr_clone . splice ()) ; expr } pub fn is_tagged_commutative (& self , expr : & syn :: Expr) -> bool { self . commutative . contains (expr) } } pub fn properties_optimize_node < 'a > (node : & mut HfPlusNode < 'a > , db : & PropertyDatabase , seen_tees : & mut SeenTees < 'a > ,) { node . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , seen_tees ,) ; match node { HfPlusNode :: ReduceKeyed { f , .. } if db . is_tagged_commutative (& f . 0) => { dbg ! ("IDENTIFIED COMMUTATIVE OPTIMIZATION for {:?}" , & f) ; } _ => { } } } pub fn properties_optimize < 'a > (ir : Vec < HfPlusLeaf < 'a > > , db : & PropertyDatabase ,) -> Vec < HfPlusLeaf < 'a > > { let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use super :: * ; use crate :: deploy :: SingleProcessGraph ; use crate :: FlowBuilder ; # [test] fn test_property_database () { let mut db = PropertyDatabase :: default () ; assert ! (! db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; let _ = db . add_commutative_tag (q ! (| a : & mut i32 , b : i32 | * a += b)) ; assert ! (db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; } # [test] fn test_property_optimized () { let flow = FlowBuilder :: new () ; let mut database = PropertyDatabase :: default () ; let process = flow . process :: < () > () ; let counter_func = q ! (| count : & mut i32 , _ | * count += 1) ; let _ = database . add_commutative_tag (counter_func) ; flow . source_iter (& process , q ! (vec ! [])) . map (q ! (| string : String | (string , ()))) . tick_batch () . fold_keyed (q ! (|| 0) , counter_func) . all_ticks () . for_each (q ! (| (string , count) | println ! ("{}: {}" , string , count))) ; let built = flow . finalize () . optimize_with (| ir | properties_optimize (ir , & database)) . with_default_optimize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let _ = built . compile_no_network :: < SingleProcessGraph > () ; } } } pub use crate :: RuntimeContext ; # [cfg (stageleft_macro)] impl Copy for RuntimeContext < '_ > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Context > for RuntimeContext < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (quote ! (& context))) } } pub use crate :: HfCompiled ; # [cfg (stageleft_macro)] impl < 'a , ID > HfCompiled < 'a , ID > { pub fn hydroflow_ir (& self) -> & BTreeMap < usize , HydroflowGraph > { & self . hydroflow_ir } } # [cfg (stageleft_macro)] impl < 'a > HfCompiled < 'a , usize > { pub fn with_dynamic_id (self , id : impl Quoted < 'a , usize >) -> HfBuiltWithId < 'a > { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; let mut conditioned_tokens = None ; for (subgraph_id , flat_graph) in self . hydroflow_ir { let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; let my_extra_stmts = self . extra_stmts . get (& subgraph_id) . cloned () . unwrap_or_default () ; if let Some (conditioned_tokens) = conditioned_tokens . as_mut () { * conditioned_tokens = syn :: parse_quote ! { # conditioned_tokens else if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } } ; } else { conditioned_tokens = Some (syn :: parse_quote ! { if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } }) ; } } let conditioned_tokens : TokenStream = conditioned_tokens . unwrap () ; let id = id . splice () ; HfBuiltWithId { tokens : syn :: parse_quote ! ({ let __given_id = # id ; # conditioned_tokens else { panic ! ("Invalid node id: {}" , __given_id) ; } }) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfCompiled < 'a , () > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfCompiled < 'a , () > { fn to_tokens (mut self) -> (Option < TokenStream > , Option < TokenStream >) { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; if self . hydroflow_ir . len () != 1 { panic ! ("Expected exactly one subgraph in the Hydroflow IR") ; } let flat_graph = self . hydroflow_ir . remove (& 0) . unwrap () ; let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; (None , Some (tokens)) } } pub use crate :: HfBuiltWithId ; # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfBuiltWithId < 'a > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfBuiltWithId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (self . tokens)) } }
[INFO] [stdout]   |
[INFO] [stdout] help: ...otherwise replace it with an invocation of macro `deref`
[INFO] [stdout]   |
[INFO] [stdout] 1 - pub use std :: collections :: BTreeMap ; pub use std :: marker :: PhantomData ; pub use hydroflow :: scheduled :: context :: Context ; pub use hydroflow :: scheduled :: graph :: Hydroflow ; pub use hydroflow :: * ; pub use lang :: graph :: { partition_graph , HydroflowGraph } ; pub use proc_macro2 :: TokenStream ; pub use quote :: quote ; pub use stageleft :: runtime_support :: FreeVariable ; pub use stageleft :: Quoted ; pub mod runtime_support { pub use bincode ; } pub mod stream { pub use std :: cell :: RefCell ; pub use std :: hash :: Hash ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow :: bytes :: Bytes ; pub use hydroflow :: futures :: Sink ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: quote ; pub use serde :: de :: DeserializeOwned ; pub use serde :: Serialize ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use syn :: parse_quote ; pub use crate :: builder :: { ClusterIds , FlowLeaves } ; pub use crate :: cycle :: { CycleCollection , CycleComplete } ; pub use crate :: ir :: { DebugInstantiate , HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { CanSend , Location , LocationId } ; pub use crate :: { Cluster , Optional , Singleton } ; pub use crate :: stream :: Unbounded ; pub use crate :: stream :: Bounded ; pub use crate :: stream :: NoTick ; pub use crate :: stream :: Tick ; pub use crate :: stream :: Stream ; # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Stream { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Stream < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Stream { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , C , N > > ,) -> Stream < 'a , (T , O) , W , C , N > where O : Clone , { let other : Optional < 'a , O , Bounded , C , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn cross_product < O > (self , other : Stream < 'a , O , W , C , N >) -> Stream < 'a , (T , O) , W , C , N > where T : Clone , O : Clone , { if self . location_kind != other . location_kind { panic ! ("cross_product must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossProduct (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn union (self , other : Stream < 'a , T , W , C , N >) -> Stream < 'a , T , W , C , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn dest_sink < S : Unpin + Sink < T > + 'a > (self , sink : impl Quoted < 'a , S >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: DestSink { sink : sink . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn first (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } # [doc = " Allow this stream through if the other stream has elements, otherwise the output is empty."] pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } # [doc = " Allow this stream through if the other stream is empty, otherwise the output is empty."] pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn enumerate (self) -> Stream < 'a , (usize , T) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Enumerate (Box :: new (self . ir_node . into_inner ())) ,) } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn sort (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Ord , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Sort (Box :: new (self . ir_node . into_inner ())) ,) } pub fn count (self) -> Singleton < 'a , usize , Bounded , Tick , N > { self . fold (q ! (|| 0usize) , q ! (| count , _ | * count += 1)) } pub fn delta (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } pub fn unique (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Eq + Hash , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unique (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn tick_batch (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_prefix (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { self . tick_batch () . persist () } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn for_each < F : Fn (T) + 'a > (self , f : impl IntoQuotedMut < 'a , F >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: ForEach { input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , f : f . splice () . into () , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Unbounded , NoTick , N > { pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . tick_batch () . continue_if (samples . first ()) . all_ticks () } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Unbounded , NoTick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , C , N : Location > Stream < 'a , T , Bounded , C , N > { pub fn filter_not_in (self , other : Stream < 'a , T , Bounded , C , N >) -> Stream < 'a , T , Bounded , C , N > where T : Eq + Hash , { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Difference (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Stream < 'a , & T , W , C , N > { pub fn cloned (self) -> Stream < 'a , T , W , C , N > { self . map (q ! (| d | d . clone ())) } } # [cfg (stageleft_macro)] impl < 'a , K , V1 , W , C , N : Location > Stream < 'a , (K , V1) , W , C , N > { pub fn join < W2 , V2 > (self , n : Stream < 'a , (K , V2) , W2 , C , N > ,) -> Stream < 'a , (K , (V1 , V2)) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Join (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } pub fn anti_join < W2 > (self , n : Stream < 'a , K , W2 , C , N >) -> Stream < 'a , (K , V1) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("anti_join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: AntiJoin (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , K : Eq + Hash , V , N : Location > Stream < 'a , (K , V) , Bounded , Tick , N > { pub fn fold_keyed < A , I : Fn () -> A + 'a , F : Fn (& mut A , V) + 'a > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , A) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FoldKeyed { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce_keyed < F : Fn (& mut V , V) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , V) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: ReduceKeyed { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } pub fn get_this_crate () -> TokenStream { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , Span :: call_site ()) ; quote ! { # ident } } } } pub fn serialize_bincode < T : Serialize > (is_demux : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if is_demux { parse_quote ! { map (| (id , data) | { (id , # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into ()) }) } } else { parse_quote ! { map (| data | { # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into () }) } } } pub fn deserialize_bincode < T : DeserializeOwned > (tagged : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if tagged { parse_quote ! { map (| res | { let (id , b) = res . unwrap () ; (id , # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& b) . unwrap ()) }) } } else { parse_quote ! { map (| res | { # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& res . unwrap ()) . unwrap () }) } } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn send_bincode < N2 : Location , CoreType > (self , other : & N2 ,) -> Stream < 'a , N :: Out < CoreType > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T > , CoreType : Serialize + DeserializeOwned , { let serialize_pipeline = Some (serialize_bincode :: < CoreType > (N :: is_demux ())) ; let deserialize_pipeline = Some (deserialize_bincode :: < CoreType > (N :: is_tagged ())) ; Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bytes < N2 : Location > (self , other : & N2 ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T > , { Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline : None , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline : if N :: is_tagged () { Some (parse_quote ! (map (| (id , b) | (id , b . unwrap () . freeze ())))) } else { Some (parse_quote ! (map (| b | b . unwrap () . freeze ()))) } , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bincode_interleaved < N2 : Location , Tag , CoreType > (self , other : & N2 ,) -> Stream < 'a , CoreType , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T , Out < CoreType > = (Tag , CoreType) > , CoreType : Serialize + DeserializeOwned , { self . send_bincode :: < N2 , CoreType > (other) . map (q ! (| (_ , b) | b)) } pub fn send_bytes_interleaved < N2 : Location , Tag > (self , other : & N2 ,) -> Stream < 'a , Bytes , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T , Out < Bytes > = (Tag , Bytes) > , { self . send_bytes :: < N2 > (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bincode < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < T > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) > , T : Clone + Serialize + DeserializeOwned , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bincode (other) } pub fn broadcast_bincode_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , T , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) , Out < T > = (Tag , T) > + 'a , T : Clone + Serialize + DeserializeOwned , { self . broadcast_bincode (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bytes < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) > + 'a , T : Clone , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bytes (other) } pub fn broadcast_bytes_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , Bytes , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) , Out < Bytes > = (Tag , Bytes) > + 'a , T : Clone , { self . broadcast_bytes (other) . map (q ! (| (_ , b) | b)) } } } pub use stream :: { Bounded , NoTick , Stream , Tick , Unbounded } ; pub mod singleton { pub use std :: cell :: RefCell ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use crate :: builder :: FlowLeaves ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial , CycleComplete } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: Stream ; pub use crate :: singleton :: CrossResult ; # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Singleton < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Singleton :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } pub use crate :: singleton :: Singleton ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Singleton { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleComplete < 'a > for Singleton < 'a , T , Bounded , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleCollectionWithInitial < 'a > for Singleton < 'a , T , Bounded , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , initial : Self , l : LocationId ,) -> Self { Singleton :: new (l , ir_leaves , HfPlusNode :: Union (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , }) , initial . ir_node . into_inner () . into () ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Singleton < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Singleton { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , U , W , C , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (Self :: other_ir_node (other)) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Singleton < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CrossSingleton (Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , Box :: new (HfPlusNode :: Unpersist (Box :: new (Self :: other_ir_node (other)))) ,))) ,) } } pub use crate :: singleton :: Optional ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Optional { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } pub fn some (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: new (singleton . location_kind , singleton . ir_leaves , singleton . ir_node . into_inner () ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > From < Singleton < 'a , T , W , C , N > > for Optional < 'a , T , W , C , N > { fn from (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: some (singleton) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Optional < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Optional { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn into_stream (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , Tick , N > > ,) -> Optional < 'a , (T , O) , Bounded , Tick , N > where O : Clone , { let other : Optional < 'a , O , Bounded , Tick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn union (self , other : Optional < 'a , T , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Optional < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_samples (self) -> Stream < 'a , T , Unbounded , NoTick , N > { self . latest_tick () . all_ticks () } pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . latest_tick () . continue_if (samples . first ()) . latest () . tick_samples () } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Unbounded , NoTick , N > > ,) -> Optional < 'a , (T , O) , Unbounded , NoTick , N > where O : Clone , { let other : Optional < 'a , O , Unbounded , NoTick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } self . latest_tick () . cross_singleton (other . latest_tick ()) . latest () } } } pub use singleton :: { Optional , Singleton } ; pub mod location { pub use std :: marker :: PhantomData ; pub use crate :: location :: LocationId ; pub use crate :: location :: Location ; pub use crate :: location :: Process ; # [cfg (stageleft_macro)] impl < P > Clone for Process < P > { fn clone (& self) -> Self { Process { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < P > Location for Process < P > { fn id (& self) -> LocationId { LocationId :: Process (self . id) } } pub use crate :: location :: Cluster ; # [cfg (stageleft_macro)] impl < C > Clone for Cluster < C > { fn clone (& self) -> Self { Cluster { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < C > Location for Cluster < C > { fn id (& self) -> LocationId { LocationId :: Cluster (self . id) } } pub use crate :: location :: CanSend ; # [cfg (stageleft_macro)] impl < P1 , P2 > CanSend < Process < P2 > > for Process < P1 > { type In < T > = T ; type Out < T > = T ; fn is_demux () -> bool { false } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < P1 , C2 > CanSend < Cluster < C2 > > for Process < P1 > { type In < T > = (u32 , T) ; type Out < T > = T ; fn is_demux () -> bool { true } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < C1 , P2 > CanSend < Process < P2 > > for Cluster < C1 > { type In < T > = T ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { false } fn is_tagged () -> bool { true } } # [cfg (stageleft_macro)] impl < C1 , C2 > CanSend < Cluster < C2 > > for Cluster < C1 > { type In < T > = (u32 , T) ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { true } fn is_tagged () -> bool { true } } } pub use location :: { Cluster , Process } ; pub mod deploy { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use stageleft :: Quoted ; pub mod graphs { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use super :: { LocalDeploy , Node , ProcessSpec } ; pub use crate :: deploy :: graphs :: SingleProcessGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for SingleProcessGraph { type Process = SingleNode ; type Cluster = SingleNode ; type Meta = () ; type GraphId = () ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { SingleNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { SingleNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , SingleProcessGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> SingleNode { SingleNode { } } } pub use crate :: deploy :: graphs :: SingleNode ; # [cfg (stageleft_macro)] impl Node for SingleNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } pub use crate :: deploy :: graphs :: MultiGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for MultiGraph { type Process = MultiNode ; type Cluster = MultiNode ; type Meta = () ; type GraphId = usize ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { MultiNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { MultiNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , MultiGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> MultiNode { MultiNode { } } } pub use crate :: deploy :: graphs :: MultiNode ; # [cfg (stageleft_macro)] impl Node for MultiNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } } pub use graphs :: * ; pub use crate :: deploy :: LocalDeploy ; pub use crate :: deploy :: Deploy ; # [cfg (stageleft_macro)] impl < 'a , T : Deploy < 'a , Process = N , Cluster = C , Meta = M , GraphId = R > , N : Node < Meta = M > , C : Node < Meta = M > , M : Default , R , > LocalDeploy < 'a > for T { type Process = N ; type Cluster = C ; type Meta = M ; type GraphId = R ; fn has_trivial_node () -> bool { < T as Deploy < 'a > > :: has_trivial_node () } fn trivial_process (id : usize) -> Self :: Process { < T as Deploy < 'a > > :: trivial_process (id) } fn trivial_cluster (id : usize) -> Self :: Cluster { < T as Deploy < 'a > > :: trivail_cluster (id) } } pub use crate :: deploy :: ProcessSpec ; pub use crate :: deploy :: ClusterSpec ; pub use crate :: deploy :: Node ; } pub use deploy :: { ClusterSpec , Deploy , ProcessSpec } ; pub mod cycle { pub use std :: marker :: PhantomData ; pub use crate :: builder :: FlowLeaves ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: cycle :: CycleComplete ; pub use crate :: cycle :: CycleCollection ; pub use crate :: cycle :: CycleCollectionWithInitial ; pub use crate :: cycle :: HfCycle ; # [cfg (stageleft_macro)] impl < 'a , S : CycleComplete < 'a > > HfCycle < 'a , S > { pub fn complete (self , stream : S) { let ident = self . ident ; S :: complete (stream , ident) } } } pub use cycle :: HfCycle ; pub mod builder { pub use std :: cell :: RefCell ; pub use std :: collections :: HashMap ; pub use std :: marker :: PhantomData ; pub use std :: rc :: Rc ; pub use std :: time :: Duration ; pub use hydroflow :: futures :: stream :: Stream as FuturesStream ; pub use hydroflow :: { tokio , tokio_stream } ; pub use internal :: TokenStream ; pub use proc_macro2 :: Span ; pub use quote :: quote ; pub use runtime_support :: FreeVariable ; pub use stageleft :: * ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Cluster , Location , LocationId , Process } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: { HfCycle , Optional , RuntimeContext , Singleton , Stream } ; pub mod built { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use hydroflow_lang :: graph :: { eliminate_extra_unions_tees , HydroflowGraph } ; pub use super :: deploy :: { DeployFlow , DeployResult } ; pub use crate :: deploy :: { ClusterSpec , Deploy , LocalDeploy , ProcessSpec } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Cluster , Process } ; pub use crate :: HfCompiled ; pub use crate :: builder :: built :: BuiltFlow ; # [cfg (stageleft_macro)] impl < 'a > Drop for BuiltFlow < 'a > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped BuiltFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn ir (& self) -> & Vec < HfPlusLeaf < 'a > > { & self . ir } pub fn optimize_with (mut self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> BuiltFlow < 'a > { self . used = true ; BuiltFlow { ir : f (std :: mem :: take (& mut self . ir)) , processes : std :: mem :: take (& mut self . processes) , clusters : std :: mem :: take (& mut self . clusters) , used : false , _phantom : PhantomData , } } } pub fn build_inner (ir : & mut Vec < HfPlusLeaf >) -> BTreeMap < usize , HydroflowGraph > { let mut builders = BTreeMap :: new () ; let mut built_tees = HashMap :: new () ; let mut next_stmt_id = 0 ; for leaf in ir { leaf . emit (& mut builders , & mut built_tees , & mut next_stmt_id) ; } builders . into_iter () . map (| (k , v) | { let (mut flat_graph , _ , _) = v . build () ; eliminate_extra_unions_tees (& mut flat_graph) ; (k , flat_graph) }) . collect () } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn compile_no_network < D : LocalDeploy < 'a > > (mut self) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; HfCompiled { hydroflow_ir : build_inner (& mut self . ir) , extra_stmts : BTreeMap :: new () , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> BuiltFlow < 'a > { self . optimize_with (crate :: persist_pullup :: persist_pullup) } fn into_deploy < D : LocalDeploy < 'a > > (mut self) -> DeployFlow < 'a , D > { self . used = true ; let processes = if D :: has_trivial_node () { self . processes . iter () . map (| id | (* id , D :: trivial_process (* id))) . collect () } else { HashMap :: new () } ; let clusters = if D :: has_trivial_node () { self . clusters . iter () . map (| id | (* id , D :: trivial_cluster (* id))) . collect () } else { HashMap :: new () } ; DeployFlow { ir : std :: mem :: take (& mut self . ir) , nodes : processes , clusters , used : false , _phantom : PhantomData , } } pub fn with_process < P , D : LocalDeploy < 'a > > (self , process : & Process < P > , spec : impl ProcessSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_process (process , spec) } pub fn with_cluster < C , D : LocalDeploy < 'a > > (self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_cluster (cluster , spec) } pub fn compile < D : Deploy < 'a > + 'a > (self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . into_deploy :: < D > () . compile (env) } pub fn deploy < D : Deploy < 'a , CompileEnv = () > + 'a > (self , env : & mut D :: InstantiateEnv ,) -> DeployResult < 'a , D > { self . into_deploy :: < D > () . deploy (env) } } } pub mod deploy { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use proc_macro2 :: Span ; pub use stageleft :: Quoted ; pub use super :: built :: build_inner ; pub use crate :: deploy :: { LocalDeploy , Node } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: { Cluster , ClusterSpec , Deploy , HfCompiled , Process , ProcessSpec } ; pub use crate :: builder :: deploy :: DeployFlow ; # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > Drop for DeployFlow < 'a , D > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped DeployFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > DeployFlow < 'a , D > { pub fn with_process < P > (mut self , process : & Process < P > , spec : impl ProcessSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < P > () . to_string () ; self . nodes . insert (process . id , spec . build (process . id , & tag_name)) ; self } pub fn with_cluster < C > (mut self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < C > () . to_string () ; self . clusters . insert (cluster . id , spec . build (cluster . id , & tag_name)) ; self } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployFlow < 'a , D > { pub fn compile (mut self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; let mut seen_tees : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | leaf . compile_network :: < D > (env , & mut seen_tees , & self . nodes , & self . clusters)) . collect () ; let extra_stmts = self . extra_stmts (env) ; HfCompiled { hydroflow_ir : build_inner (& mut ir_leaves_networked) , extra_stmts , _phantom : PhantomData , } } fn extra_stmts (& self , env : & < D as Deploy < 'a > > :: CompileEnv) -> BTreeMap < usize , Vec < syn :: Stmt > > { let all_locations_count = self . nodes . len () + self . clusters . len () ; let mut extra_stmts : BTreeMap < usize , Vec < syn :: Stmt > > = BTreeMap :: new () ; for & c_id in self . clusters . keys () { let self_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , c_id) , Span :: call_site () ,) ; let self_id_expr = D :: cluster_self_id (env) . splice () ; extra_stmts . entry (c_id) . or_default () . push (syn :: parse_quote ! { let # self_id_ident = # self_id_expr ; }) ; for other_location in 0 .. all_locations_count { let other_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , c_id) , Span :: call_site () ,) ; let other_id_expr = D :: cluster_ids (env , c_id) . splice () ; extra_stmts . entry (other_location) . or_default () . push (syn :: parse_quote ! { let # other_id_ident = # other_id_expr ; }) ; } } extra_stmts } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a , CompileEnv = () > > DeployFlow < 'a , D > { # [must_use] pub fn deploy (mut self , env : & mut D :: InstantiateEnv) -> DeployResult < 'a , D > { self . used = true ; let mut seen_tees_instantiate : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | { leaf . compile_network :: < D > (& () , & mut seen_tees_instantiate , & self . nodes , & self . clusters ,) }) . collect () ; let mut compiled = build_inner (& mut ir_leaves_networked) ; let mut extra_stmts = self . extra_stmts (& ()) ; let mut meta = D :: Meta :: default () ; let (mut processes , mut clusters) = (std :: mem :: take (& mut self . nodes) . into_iter () . map (| (node_id , node) | { node . instantiate (env , & mut meta , compiled . remove (& node_id) . unwrap () , extra_stmts . remove (& node_id) . unwrap_or_default () ,) ; (node_id , node) }) . collect :: < HashMap < _ , _ > > () , std :: mem :: take (& mut self . clusters) . into_iter () . map (| (cluster_id , cluster) | { cluster . instantiate (env , & mut meta , compiled . remove (& cluster_id) . unwrap () , extra_stmts . remove (& cluster_id) . unwrap_or_default () ,) ; (cluster_id , cluster) }) . collect :: < HashMap < _ , _ > > () ,) ; for node in processes . values_mut () { node . update_meta (& meta) ; } for cluster in clusters . values_mut () { cluster . update_meta (& meta) ; } let mut seen_tees_connect = HashMap :: new () ; for leaf in ir_leaves_networked { leaf . connect_network (& mut seen_tees_connect) ; } DeployResult { processes , clusters , } } } pub use crate :: builder :: deploy :: DeployResult ; # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployResult < 'a , D > { pub fn get_process < P > (& self , p : & Process < P >) -> & D :: Process { let id = match p . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . processes . get (& id) . unwrap () } pub fn get_cluster < C > (& self , c : & Cluster < C >) -> & D :: Cluster { let id = match c . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . clusters . get (& id) . unwrap () } } } # [doc = " Tracks the leaves of the dataflow IR. This is referenced by"] # [doc = " `Stream` and `HfCycle` to build the IR. The inner option will"] # [doc = " be set to `None` when this builder is finalized."] pub type FlowLeaves < 'a > = Rc < RefCell < Option < Vec < HfPlusLeaf < 'a > > > > > ; pub use crate :: builder :: ClusterIds ; # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Vec < u32 > > for ClusterIds < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , & 'a Vec < u32 > > for ClusterIds < 'a > { } # [derive (Copy , Clone)] pub struct ClusterSelfId < 'a > { pub id : usize , pub _phantom : PhantomData < & 'a mut & 'a u32 > , } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < u32 > for ClusterSelfId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , u32 > for ClusterSelfId < 'a > { } pub use crate :: builder :: FlowBuilder ; # [cfg (stageleft_macro)] impl < 'a > Drop for FlowBuilder < 'a > { fn drop (& mut self) { if ! self . finalized { panic ! ("Dropped FlowBuilder without finalizing, you may have forgotten to call `with_default_optimize`, `optimize_with`, or `finalize`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > QuotedContext for FlowBuilder < 'a > { fn create () -> Self { FlowBuilder :: new () } } # [cfg (stageleft_macro)] impl < 'a > FlowBuilder < 'a > { # [allow (clippy :: new_without_default)] pub fn new () -> FlowBuilder < 'a > { FlowBuilder { ir_leaves : Rc :: new (RefCell :: new (Some (Vec :: new ()))) , nodes : RefCell :: new (vec ! []) , clusters : RefCell :: new (vec ! []) , cycle_ids : RefCell :: new (HashMap :: new ()) , next_node_id : RefCell :: new (0) , finalized : false , _phantom : PhantomData , } } pub fn finalize (mut self) -> built :: BuiltFlow < 'a > { self . finalized = true ; built :: BuiltFlow { ir : self . ir_leaves . borrow_mut () . take () . unwrap () , processes : self . nodes . replace (vec ! []) , clusters : self . clusters . replace (vec ! []) , used : false , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> built :: BuiltFlow < 'a > { self . finalize () . with_default_optimize () } pub fn optimize_with (self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> built :: BuiltFlow < 'a > { self . finalize () . optimize_with (f) } pub fn ir_leaves (& self) -> & FlowLeaves < 'a > { & self . ir_leaves } pub fn process < P > (& self) -> Process < P > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . nodes . borrow_mut () . push (id) ; Process { id , _phantom : PhantomData , } } pub fn cluster < C > (& self) -> Cluster < C > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . clusters . borrow_mut () . push (id) ; Cluster { id , _phantom : PhantomData , } } pub fn runtime_context (& self) -> RuntimeContext < 'a > { RuntimeContext { _phantom : PhantomData , } } pub fn cluster_members < C > (& self , cluster : & Cluster < C > ,) -> impl Quoted < 'a , & 'a Vec < u32 > > + Copy + 'a { ClusterIds { id : cluster . id , _phantom : PhantomData , } } pub fn cluster_self_id < C > (& self , cluster : & Cluster < C >) -> impl Quoted < 'a , u32 > + Copy + 'a { ClusterSelfId { id : cluster . id , _phantom : PhantomData , } } pub fn spin < L : Location > (& self , on : & L) -> Stream < 'a , () , Unbounded , NoTick , L > { Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Spin () , location_kind : on . id () , })) ,) } pub fn spin_batch < L : Location > (& self , on : & L , batch_size : impl Quoted < 'a , usize > + Copy + 'a ,) -> Stream < 'a , () , Bounded , Tick , L > { self . spin (on) . flat_map (q ! (move | _ | 0 .. batch_size)) . map (q ! (| _ | ())) . tick_batch () } pub fn source_stream < T , E : FuturesStream < Item = T > + Unpin , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Unbounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Stream (e . into ()) , location_kind : on . id () , })) ,) } pub fn source_iter < T , E : IntoIterator < Item = T > , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Bounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , })) ,) } pub fn singleton < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Singleton < 'a , T , Bounded , NoTick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Singleton :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,)))) ,) } pub fn singleton_first_tick < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Optional < 'a , T , Bounded , Tick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,) } pub fn source_interval < L : Location > (& self , on : & L , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , () , Unbounded , NoTick , L > { let interval = interval . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : on . id () , })) ,) } pub fn source_interval_delayed < L : Location > (& self , on : & L , delay : impl Quoted < 'a , Duration > + Copy + 'a , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , tokio :: time :: Instant , Unbounded , NoTick , L > { self . source_stream (on , q ! (tokio_stream :: wrappers :: IntervalStream :: new (tokio :: time :: interval_at (tokio :: time :: Instant :: now () + delay , interval))) ,) . tick_batch () . first () . latest () } pub fn cycle < S : CycleCollection < 'a > > (& self , on : & S :: Location) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , on . id ()) ,) } pub fn cycle_with_initial < S : CycleCollectionWithInitial < 'a > > (& self , on : & S :: Location , initial : S ,) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , initial , on . id ()) ,) } } } pub use builder :: FlowBuilder ; pub mod ir { pub use core :: panic ; pub use std :: cell :: RefCell ; pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow_lang :: graph :: FlatGraphBuilder ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: ToTokens ; pub use syn :: parse_quote ; pub use crate :: deploy :: Deploy ; pub use crate :: location :: LocationId ; pub use crate :: ir :: DebugExpr ; # [cfg (stageleft_macro)] impl From < syn :: Expr > for DebugExpr { fn from (expr : syn :: Expr) -> DebugExpr { DebugExpr (expr) } } # [cfg (stageleft_macro)] impl Deref for DebugExpr { type Target = syn :: Expr ; fn deref (& self) -> & Self :: Target { & self . 0 } } # [cfg (stageleft_macro)] impl ToTokens for DebugExpr { fn to_tokens (& self , tokens : & mut TokenStream) { self . 0 . to_tokens (tokens) ; } } # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugExpr { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "{}" , self . 0 . to_token_stream ()) } } pub use crate :: ir :: DebugInstantiate ; # [cfg (stageleft_macro)] impl < 'a > std :: fmt :: Debug for DebugInstantiate < 'a > { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<network instantiate>") } } pub use crate :: ir :: DebugPipelineFn ; # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugPipelineFn { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<function>") } } pub use crate :: ir :: HfPlusSource ; pub use crate :: ir :: HfPlusLeaf ; # [cfg (stageleft_macro)] impl < 'a > HfPlusLeaf < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . compile_network :: < D > (compile_env , s , nodes , clusters) ; } , seen_tees ,) } pub fn connect_network (self , seen_tees : & mut SeenTees < 'a >) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . connect_network (s) ; } , seen_tees ,) } pub fn transform_children (self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) -> HfPlusLeaf < 'a > { match self { HfPlusLeaf :: ForEach { f , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: ForEach { f , input } } HfPlusLeaf :: DestSink { sink , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: DestSink { sink , input } } HfPlusLeaf :: CycleSink { ident , location_kind , mut input , } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: CycleSink { ident , location_kind , input , } } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) { match self { HfPlusLeaf :: ForEach { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> for_each (# f) ; }) ; } HfPlusLeaf :: DestSink { sink , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink) ; }) ; } HfPlusLeaf :: CycleSink { ident , location_kind , input , } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; assert_eq ! (input_location_id , * location_id , "cycle_sink location mismatch") ; graph_builders . entry (* location_id) . or_default () . add_statement (parse_quote ! { # ident = # input_ident ; }) ; } } } } pub use crate :: ir :: HfPlusNode ; pub type SeenTees < 'a > = HashMap < * const RefCell < HfPlusNode < 'a > > , Rc < RefCell < HfPlusNode < 'a > > > > ; # [cfg (stageleft_macro)] impl < 'a > HfPlusNode < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (& mut self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) { self . transform_children (| n , s | n . compile_network :: < D > (compile_env , s , nodes , clusters) , seen_tees ,) ; if let HfPlusNode :: Network { from_location , to_location , instantiate_fn , .. } = self { let (sink_expr , source_expr , connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { let ((sink , source) , connect_fn) = match (from_location , to_location) { (LocationId :: Process (from) , LocationId :: Process (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: o2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Process (from) , LocationId :: Cluster (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: o2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Process (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: m2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Cluster (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: m2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } } ; (sink , source , connect_fn) } DebugInstantiate :: Finalized (_ , _ , _) => panic ! ("network already finalized") , } ; * instantiate_fn = DebugInstantiate :: Finalized (sink_expr , source_expr , connect_fn) ; } } pub fn connect_network (& mut self , seen_tees : & mut SeenTees < 'a >) { self . transform_children (| n , s | n . connect_network (s) , seen_tees) ; if let HfPlusNode :: Network { instantiate_fn , .. } = self { match instantiate_fn { DebugInstantiate :: Building () => panic ! ("network not built") , DebugInstantiate :: Finalized (_ , _ , ref connect_fn) => { connect_fn () ; } } } } pub fn transform_children (& mut self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) { match self { HfPlusNode :: Placeholder => { panic ! () ; } HfPlusNode :: Source { .. } => { } HfPlusNode :: CycleSource { .. } => { } HfPlusNode :: Tee { inner } => { if let Some (transformed) = seen_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { * inner = transformed . clone () ; } else { let transformed_cell = Rc :: new (RefCell :: new (HfPlusNode :: Placeholder)) ; seen_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , transformed_cell . clone () ,) ; let mut orig = inner . replace (HfPlusNode :: Placeholder) ; transform (& mut orig , seen_tees) ; * transformed_cell . borrow_mut () = orig ; * inner = transformed_cell ; } } HfPlusNode :: Persist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Unpersist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Delta (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Union (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossProduct (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossSingleton (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Join (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Difference (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: AntiJoin (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Map { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FlatMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Filter { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FilterMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Sort (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: DeferTick (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Enumerate (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Inspect { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Unique (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Fold { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FoldKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Reduce { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: ReduceKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Network { input , .. } => { transform (input . as_mut () , seen_tees) ; } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) -> (syn :: Ident , usize) { match self { HfPlusNode :: Placeholder => { panic ! () } HfPlusNode :: Persist (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let persist_id = * next_stmt_id ; * next_stmt_id += 1 ; let persist_ident = syn :: Ident :: new (& format ! ("stream_{}" , persist_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # persist_ident = # inner_ident -> persist ::<'static > () ; }) ; (persist_ident , location) } HfPlusNode :: Unpersist (_) => { panic ! ("Unpersist is a marker node and should have been optimized away. This is likely a compiler bug.") } HfPlusNode :: Delta (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let delta_id = * next_stmt_id ; * next_stmt_id += 1 ; let delta_ident = syn :: Ident :: new (& format ! ("stream_{}" , delta_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # delta_ident = # inner_ident -> multiset_delta () ; }) ; (delta_ident , location) } HfPlusNode :: Source { source , location_kind , } => { let source_id = * next_stmt_id ; * next_stmt_id += 1 ; let source_ident = syn :: Ident :: new (& format ! ("stream_{}" , source_id) , Span :: call_site ()) ; let source_stmt = match source { HfPlusSource :: Stream (expr) => { parse_quote ! { # source_ident = source_stream (# expr) ; } } HfPlusSource :: Iter (expr) => { parse_quote ! { # source_ident = source_iter (# expr) ; } } HfPlusSource :: Interval (expr) => { parse_quote ! { # source_ident = source_interval (# expr) ; } } HfPlusSource :: Spin () => { parse_quote ! { # source_ident = spin () ; } } } ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; graph_builders . entry (* location_id) . or_default () . add_statement (source_stmt) ; (source_ident , * location_id) } HfPlusNode :: CycleSource { ident , location_kind , } => { let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; (ident . clone () , * location_id) } HfPlusNode :: Tee { inner } => { if let Some (ret) = built_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { ret . clone () } else { let (inner_ident , inner_location_id) = inner . borrow () . emit (graph_builders , built_tees , next_stmt_id) ; let tee_id = * next_stmt_id ; * next_stmt_id += 1 ; let tee_ident = syn :: Ident :: new (& format ! ("stream_{}" , tee_id) , Span :: call_site ()) ; let builder = graph_builders . entry (inner_location_id) . or_default () ; builder . add_statement (parse_quote ! { # tee_ident = # inner_ident -> tee () ; }) ; built_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , (tee_ident . clone () , inner_location_id) ,) ; (tee_ident , inner_location_id) } } HfPlusNode :: Union (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "union inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let union_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # union_ident = union () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [0] # union_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # union_ident ; }) ; (union_ident , left_location_id) } HfPlusNode :: CrossSingleton (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "cross_singleton inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let cross_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # cross_ident = cross_singleton () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [input] # cross_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [single] # cross_ident ; }) ; (cross_ident , left_location_id) } HfPlusNode :: CrossProduct (..) | HfPlusNode :: Join (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: CrossProduct (..)) { parse_quote ! (cross_join_multiset) } else { parse_quote ! (join_multiset) } ; let (HfPlusNode :: CrossProduct (left , right) | HfPlusNode :: Join (left , right)) = self else { unreachable ! () } ; let (left_inner , left_was_persist) = if let HfPlusNode :: Persist (left) = left . as_ref () { (left , true) } else { (left , false) } ; let (right_inner , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left_inner . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right_inner . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "join / cross product inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; match (left_was_persist , right_was_persist) { (true , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'static > () ; }) ; } (true , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'tick > () ; }) ; } (false , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } (false , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } } ; builder . add_statement (parse_quote ! { # left_ident -> [0] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Difference (..) | HfPlusNode :: AntiJoin (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Difference (..)) { parse_quote ! (difference_multiset) } else { parse_quote ! (anti_join_multiset) } ; let (HfPlusNode :: Difference (left , right) | HfPlusNode :: AntiJoin (left , right)) = self else { unreachable ! () } ; let (right , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "difference / anti join inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; if right_was_persist { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } else { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } builder . add_statement (parse_quote ! { # left_ident -> [pos] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [neg] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Map { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let map_id = * next_stmt_id ; * next_stmt_id += 1 ; let map_ident = syn :: Ident :: new (& format ! ("stream_{}" , map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # map_ident = # input_ident -> map (# f) ; }) ; (map_ident , input_location_id) } HfPlusNode :: FlatMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let flat_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let flat_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , flat_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # flat_map_ident = # input_ident -> flat_map (# f) ; }) ; (flat_map_ident , input_location_id) } HfPlusNode :: Filter { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_ident = # input_ident -> filter (# f) ; }) ; (filter_ident , input_location_id) } HfPlusNode :: FilterMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_map_ident = # input_ident -> filter_map (# f) ; }) ; (filter_map_ident , input_location_id) } HfPlusNode :: Sort (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sort_id = * next_stmt_id ; * next_stmt_id += 1 ; let sort_ident = syn :: Ident :: new (& format ! ("stream_{}" , sort_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # sort_ident = # input_ident -> sort () ; }) ; (sort_ident , input_location_id) } HfPlusNode :: DeferTick (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let defer_tick_id = * next_stmt_id ; * next_stmt_id += 1 ; let defer_tick_ident = syn :: Ident :: new (& format ! ("stream_{}" , defer_tick_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # defer_tick_ident = # input_ident -> defer_tick_lazy () ; }) ; (defer_tick_ident , input_location_id) } HfPlusNode :: Enumerate (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let enumerate_id = * next_stmt_id ; * next_stmt_id += 1 ; let enumerate_ident = syn :: Ident :: new (& format ! ("stream_{}" , enumerate_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # enumerate_ident = # input_ident -> enumerate () ; }) ; (enumerate_ident , input_location_id) } HfPlusNode :: Inspect { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let inspect_id = * next_stmt_id ; * next_stmt_id += 1 ; let inspect_ident = syn :: Ident :: new (& format ! ("stream_{}" , inspect_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # inspect_ident = # input_ident -> inspect (# f) ; }) ; (inspect_ident , input_location_id) } HfPlusNode :: Unique (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let unique_id = * next_stmt_id ; * next_stmt_id += 1 ; let unique_ident = syn :: Ident :: new (& format ! ("stream_{}" , unique_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # unique_ident = # input_ident -> unique ::<'tick > () ; }) ; (unique_ident , input_location_id) } HfPlusNode :: Fold { .. } | HfPlusNode :: FoldKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Fold { .. }) { parse_quote ! (fold) } else { parse_quote ! (fold_keyed) } ; let (HfPlusNode :: Fold { init , acc , input } | HfPlusNode :: FoldKeyed { init , acc , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let fold_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'static > (# init , # acc) ; }) ; } else { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'tick > (# init , # acc) ; }) ; } (fold_ident , input_location_id) } HfPlusNode :: Reduce { .. } | HfPlusNode :: ReduceKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Reduce { .. }) { parse_quote ! (reduce) } else { parse_quote ! (reduce_keyed) } ; let (HfPlusNode :: Reduce { f , input } | HfPlusNode :: ReduceKeyed { f , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let reduce_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'static > (# f) ; }) ; } else { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'tick > (# f) ; }) ; } (reduce_ident , input_location_id) } HfPlusNode :: Network { from_location : _ , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input , } => { let (sink_expr , source_expr , _connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { panic ! ("Expected the network to be finalized") } DebugInstantiate :: Finalized (sink , source , connect_fn) => { (sink , source , connect_fn) } } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sender_builder = graph_builders . entry (input_location_id) . or_default () ; if let Some (serialize_pipeline) = serialize_pipeline { sender_builder . add_statement (parse_quote ! { # input_ident -> # serialize_pipeline -> dest_sink (# sink_expr) ; }) ; } else { sender_builder . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink_expr) ; }) ; } let to_id = match to_location { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let receiver_builder = graph_builders . entry (* to_id) . or_default () ; let receiver_stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let receiver_stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , receiver_stream_id) , Span :: call_site ()) ; if let Some (deserialize_pipeline) = deserialize_pipeline { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) -> # deserialize_pipeline ; }) ; } else { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) ; }) ; } (receiver_stream_ident , * to_id) } } } } } pub mod persist_pullup { pub use std :: cell :: RefCell ; pub use std :: collections :: HashSet ; pub use std :: ops :: Deref ; pub use crate :: ir :: * ; pub fn persist_pullup_node < 'a > (node : & mut HfPlusNode < 'a > , seen_tees : & mut SeenTees < 'a > , persist_pulled_tees : & mut HashSet < * const RefCell < HfPlusNode < 'a > > > ,) { node . transform_children (| n , s | persist_pullup_node (n , s , persist_pulled_tees) , seen_tees ,) ; match node { HfPlusNode :: Unpersist (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Unpersist (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Delta (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Delta (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Tee { inner } => { if persist_pulled_tees . contains (& (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >)) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } else { let inner_borrow = inner . borrow () ; if let HfPlusNode :: Persist (_) = inner_borrow . deref () { drop (inner_borrow) ; persist_pulled_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >) ; if let HfPlusNode :: Persist (box behind_persist) = inner . replace (HfPlusNode :: Placeholder) { * inner . borrow_mut () = behind_persist ; } else { unreachable ! () } * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } } } HfPlusNode :: Map { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Map { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Map { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: FlatMap { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: FlatMap { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: FlatMap { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Filter { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Filter { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Filter { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Network { input : box HfPlusNode :: Persist (_) , .. } => { if let HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Union (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Union (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Union (left , right))) ; } else { unreachable ! () } } HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: CrossProduct (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,) ,)))) ; } else { unreachable ! () } } HfPlusNode :: Join (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Join (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: Join (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,))))) ; } else { unreachable ! () } } _ => { } } } pub fn persist_pullup (ir : Vec < HfPlusLeaf >) -> Vec < HfPlusLeaf > { let mut seen_tees = Default :: default () ; let mut persist_pulled_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| n , s | persist_pullup_node (n , s , & mut persist_pulled_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn persist_pullup_through_map () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } # [test] fn persist_pullup_behind_tee () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; let before_tee = flow . source_iter (& process , q ! (0 .. 10)) . tick_batch () . persist () ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } } } pub mod profiler { pub use std :: cell :: RefCell ; pub use hydroflow :: futures :: channel :: mpsc :: UnboundedSender ; pub use stageleft :: * ; pub use crate as hydroflow_plus ; pub use crate :: ir :: * ; pub use crate :: RuntimeContext ; pub fn increment_counter (count : & mut u64) { * count += 1 ; } pub fn quoted_any_fn < 'a , F : Fn (& usize) + 'a , Q : IntoQuotedMut < 'a , F > > (q : Q) -> Q { q } # [doc = " Add a profiling node before each node to count the cardinality of its input"] pub fn add_profiling_node < 'a > (node : & mut HfPlusNode < 'a > , _context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > , id : & mut u32 , seen_tees : & mut SeenTees < 'a > ,) { let my_id = * id ; * id += 1 ; node . transform_children (| node , seen_tees | { add_profiling_node (node , _context , counters , counter_queue , id , seen_tees) } , seen_tees ,) ; let orig_node = std :: mem :: replace (node , HfPlusNode :: Placeholder) ; * node = HfPlusNode :: Inspect { f : quoted_any_fn (q ! ({ counter_queue . borrow () . unbounded_send ((my_id as usize , counters . borrow () [my_id as usize])) . unwrap () ; counters . borrow_mut () [my_id as usize] = 0 ; move | _ | { hydroflow_plus :: profiler :: increment_counter (& mut counters . borrow_mut () [my_id as usize] ,) ; } })) . splice () . into () , input : Box :: new (orig_node) , } } # [doc = " Count the cardinality of each input and periodically output to a file"] pub fn profiling < 'a > (ir : Vec < HfPlusLeaf < 'a > > , context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > ,) -> Vec < HfPlusLeaf < 'a > > { let mut id = 0 ; let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | { add_profiling_node (node , context , counters , counter_queue , & mut id , seen_tees) } , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn profiler_wrapping_all_operators () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let runtime_context = flow . runtime_context () ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (& built . ir ()) ; let counters = RuntimeData :: new ("Fake") ; let counter_queue = RuntimeData :: new ("Fake") ; let pushed_down = built . with_default_optimize () . optimize_with (| ir | super :: profiling (ir , runtime_context , counters , counter_queue)) ; insta :: assert_debug_snapshot ! (& pushed_down . ir ()) ; let _ = pushed_down . compile_no_network :: < MultiGraph > () ; } } } pub mod properties { pub use std :: collections :: HashSet ; pub use stageleft :: * ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , SeenTees } ; pub use crate :: properties :: PropertyDatabase ; # [doc = " Allows us to convert the hydroflow datatype for folds to a binary operation for the algebra"] # [doc = " property tests."] # [allow (dead_code)] pub fn convert_hf_to_binary < I , A : Default , F : Fn (& mut A , I) > (f : F) -> impl Fn (I , I) -> A { move | a , b | { let mut acc = Default :: default () ; f (& mut acc , a) ; f (& mut acc , b) ; acc } } # [cfg (stageleft_macro)] impl PropertyDatabase { # [doc = " Tags the expression as commutative."] pub fn add_commutative_tag < 'a , I , A , F : Fn (& mut A , I) , Q : Quoted < 'a , F > + Clone > (& mut self , expr : Q ,) -> Q { let expr_clone = expr . clone () ; self . commutative . insert (expr_clone . splice ()) ; expr } pub fn is_tagged_commutative (& self , expr : & syn :: Expr) -> bool { self . commutative . contains (expr) } } pub fn properties_optimize_node < 'a > (node : & mut HfPlusNode < 'a > , db : & PropertyDatabase , seen_tees : & mut SeenTees < 'a > ,) { node . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , seen_tees ,) ; match node { HfPlusNode :: ReduceKeyed { f , .. } if db . is_tagged_commutative (& f . 0) => { dbg ! ("IDENTIFIED COMMUTATIVE OPTIMIZATION for {:?}" , & f) ; } _ => { } } } pub fn properties_optimize < 'a > (ir : Vec < HfPlusLeaf < 'a > > , db : & PropertyDatabase ,) -> Vec < HfPlusLeaf < 'a > > { let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use super :: * ; use crate :: deploy :: SingleProcessGraph ; use crate :: FlowBuilder ; # [test] fn test_property_database () { let mut db = PropertyDatabase :: default () ; assert ! (! db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; let _ = db . add_commutative_tag (q ! (| a : & mut i32 , b : i32 | * a += b)) ; assert ! (db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; } # [test] fn test_property_optimized () { let flow = FlowBuilder :: new () ; let mut database = PropertyDatabase :: default () ; let process = flow . process :: < () > () ; let counter_func = q ! (| count : & mut i32 , _ | * count += 1) ; let _ = database . add_commutative_tag (counter_func) ; flow . source_iter (& process , q ! (vec ! [])) . map (q ! (| string : String | (string , ()))) . tick_batch () . fold_keyed (q ! (|| 0) , counter_func) . all_ticks () . for_each (q ! (| (string , count) | println ! ("{}: {}" , string , count))) ; let built = flow . finalize () . optimize_with (| ir | properties_optimize (ir , & database)) . with_default_optimize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let _ = built . compile_no_network :: < SingleProcessGraph > () ; } } } pub use crate :: RuntimeContext ; # [cfg (stageleft_macro)] impl Copy for RuntimeContext < '_ > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Context > for RuntimeContext < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (quote ! (& context))) } } pub use crate :: HfCompiled ; # [cfg (stageleft_macro)] impl < 'a , ID > HfCompiled < 'a , ID > { pub fn hydroflow_ir (& self) -> & BTreeMap < usize , HydroflowGraph > { & self . hydroflow_ir } } # [cfg (stageleft_macro)] impl < 'a > HfCompiled < 'a , usize > { pub fn with_dynamic_id (self , id : impl Quoted < 'a , usize >) -> HfBuiltWithId < 'a > { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; let mut conditioned_tokens = None ; for (subgraph_id , flat_graph) in self . hydroflow_ir { let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; let my_extra_stmts = self . extra_stmts . get (& subgraph_id) . cloned () . unwrap_or_default () ; if let Some (conditioned_tokens) = conditioned_tokens . as_mut () { * conditioned_tokens = syn :: parse_quote ! { # conditioned_tokens else if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } } ; } else { conditioned_tokens = Some (syn :: parse_quote ! { if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } }) ; } } let conditioned_tokens : TokenStream = conditioned_tokens . unwrap () ; let id = id . splice () ; HfBuiltWithId { tokens : syn :: parse_quote ! ({ let __given_id = # id ; # conditioned_tokens else { panic ! ("Invalid node id: {}" , __given_id) ; } }) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfCompiled < 'a , () > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfCompiled < 'a , () > { fn to_tokens (mut self) -> (Option < TokenStream > , Option < TokenStream >) { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; if self . hydroflow_ir . len () != 1 { panic ! ("Expected exactly one subgraph in the Hydroflow IR") ; } let flat_graph = self . hydroflow_ir . remove (& 0) . unwrap () ; let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; (None , Some (tokens)) } } pub use crate :: HfBuiltWithId ; # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfBuiltWithId < 'a > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfBuiltWithId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (self . tokens)) } }
[INFO] [stdout] 1 + pub use std :: collections :: BTreeMap ; pub use std :: marker :: PhantomData ; pub use hydroflow :: scheduled :: context :: Context ; pub use hydroflow :: scheduled :: graph :: Hydroflow ; pub use hydroflow :: * ; pub use lang :: graph :: { partition_graph , HydroflowGraph } ; pub use proc_macro2 :: TokenStream ; pub use quote :: quote ; pub use stageleft :: runtime_support :: FreeVariable ; pub use stageleft :: Quoted ; pub mod runtime_support { pub use bincode ; } pub mod stream { pub use std :: cell :: RefCell ; pub use std :: hash :: Hash ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow :: bytes :: Bytes ; pub use hydroflow :: futures :: Sink ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: quote ; pub use serde :: de :: DeserializeOwned ; pub use serde :: Serialize ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use syn :: parse_quote ; pub use crate :: builder :: { ClusterIds , FlowLeaves } ; pub use crate :: cycle :: { CycleCollection , CycleComplete } ; pub use crate :: ir :: { DebugInstantiate , HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { CanSend , Location , LocationId } ; pub use crate :: { Cluster , Optional , Singleton } ; pub use crate :: stream :: Unbounded ; pub use crate :: stream :: Bounded ; pub use crate :: stream :: NoTick ; pub use crate :: stream :: Tick ; pub use crate :: stream :: Stream ; # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Stream { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Stream < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Stream { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , C , N > > ,) -> Stream < 'a , (T , O) , W , C , N > where O : Clone , { let other : Optional < 'a , O , Bounded , C , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn cross_product < O > (self , other : Stream < 'a , O , W , C , N >) -> Stream < 'a , (T , O) , W , C , N > where T : Clone , O : Clone , { if self . location_kind != other . location_kind { panic ! ("cross_product must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossProduct (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn union (self , other : Stream < 'a , T , W , C , N >) -> Stream < 'a , T , W , C , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn dest_sink < S : Unpin + Sink < T > + 'a > (self , sink : impl Quoted < 'a , S >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: DestSink { sink : sink . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn first (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } # [doc = " Allow this stream through if the other stream has elements, otherwise the output is empty."] pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } # [doc = " Allow this stream through if the other stream is empty, otherwise the output is empty."] pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn enumerate (self) -> Stream < 'a , (usize , T) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Enumerate (Box :: new (self . ir_node . into_inner ())) ,) } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn sort (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Ord , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Sort (Box :: new (self . ir_node . into_inner ())) ,) } pub fn count (self) -> Singleton < 'a , usize , Bounded , Tick , N > { self . fold (q ! (|| 0usize) , q ! (| count , _ | * count += 1)) } pub fn delta (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } pub fn unique (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Eq + Hash , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unique (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn tick_batch (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_prefix (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { self . tick_batch () . persist () } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn for_each < F : Fn (T) + 'a > (self , f : impl IntoQuotedMut < 'a , F >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: ForEach { input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , f : f . splice () . into () , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Unbounded , NoTick , N > { pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . tick_batch () . continue_if (samples . first ()) . all_ticks () } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Unbounded , NoTick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , C , N : Location > Stream < 'a , T , Bounded , C , N > { pub fn filter_not_in (self , other : Stream < 'a , T , Bounded , C , N >) -> Stream < 'a , T , Bounded , C , N > where T : Eq + Hash , { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Difference (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Stream < 'a , & T , W , C , N > { pub fn cloned (self) -> Stream < 'a , T , W , C , N > { self . map (q ! (| d | d . clone ())) } } # [cfg (stageleft_macro)] impl < 'a , K , V1 , W , C , N : Location > Stream < 'a , (K , V1) , W , C , N > { pub fn join < W2 , V2 > (self , n : Stream < 'a , (K , V2) , W2 , C , N > ,) -> Stream < 'a , (K , (V1 , V2)) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Join (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } pub fn anti_join < W2 > (self , n : Stream < 'a , K , W2 , C , N >) -> Stream < 'a , (K , V1) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("anti_join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: AntiJoin (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , K : Eq + Hash , V , N : Location > Stream < 'a , (K , V) , Bounded , Tick , N > { pub fn fold_keyed < A , I : Fn () -> A + 'a , F : Fn (& mut A , V) + 'a > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , A) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FoldKeyed { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce_keyed < F : Fn (& mut V , V) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , V) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: ReduceKeyed { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } pub fn get_this_crate () -> TokenStream { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , Span :: call_site ()) ; quote ! { # ident } } } } pub fn serialize_bincode < T : Serialize > (is_demux : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if is_demux { parse_quote ! { map (| (id , data) | { (id , # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into ()) }) } } else { parse_quote ! { map (| data | { # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into () }) } } } pub fn deserialize_bincode < T : DeserializeOwned > (tagged : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if tagged { parse_quote ! { map (| res | { let (id , b) = res . unwrap () ; (id , # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& b) . unwrap ()) }) } } else { parse_quote ! { map (| res | { # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& res . unwrap ()) . unwrap () }) } } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn send_bincode < N2 : Location , CoreType > (self , other : & N2 ,) -> Stream < 'a , N :: Out < CoreType > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T > , CoreType : Serialize + DeserializeOwned , { let serialize_pipeline = Some (serialize_bincode :: < CoreType > (N :: is_demux ())) ; let deserialize_pipeline = Some (deserialize_bincode :: < CoreType > (N :: is_tagged ())) ; Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bytes < N2 : Location > (self , other : & N2 ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T > , { Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline : None , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline : if N :: is_tagged () { Some (parse_quote ! (map (| (id , b) | (id , b . unwrap () . freeze ())))) } else { Some (parse_quote ! (map (| b | b . unwrap () . freeze ()))) } , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bincode_interleaved < N2 : Location , Tag , CoreType > (self , other : & N2 ,) -> Stream < 'a , CoreType , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T , Out < CoreType > = (Tag , CoreType) > , CoreType : Serialize + DeserializeOwned , { self . send_bincode :: < N2 , CoreType > (other) . map (q ! (| (_ , b) | b)) } pub fn send_bytes_interleaved < N2 : Location , Tag > (self , other : & N2 ,) -> Stream < 'a , Bytes , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T , Out < Bytes > = (Tag , Bytes) > , { self . send_bytes :: < N2 > (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bincode < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < T > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) > , T : Clone + Serialize + DeserializeOwned , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bincode (other) } pub fn broadcast_bincode_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , T , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) , Out < T > = (Tag , T) > + 'a , T : Clone + Serialize + DeserializeOwned , { self . broadcast_bincode (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bytes < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) > + 'a , T : Clone , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bytes (other) } pub fn broadcast_bytes_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , Bytes , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) , Out < Bytes > = (Tag , Bytes) > + 'a , T : Clone , { self . broadcast_bytes (other) . map (q ! (| (_ , b) | b)) } } } pub use stream :: { Bounded , NoTick , Stream , Tick , Unbounded } ; pub mod singleton { pub use std :: cell :: RefCell ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use crate :: builder :: FlowLeaves ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial , CycleComplete } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: Stream ; pub use crate :: singleton :: CrossResult ; # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Singleton < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Singleton :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } pub use crate :: singleton :: Singleton ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Singleton { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleComplete < 'a > for Singleton < 'a , T , Bounded , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleCollectionWithInitial < 'a > for Singleton < 'a , T , Bounded , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , initial : Self , l : LocationId ,) -> Self { Singleton :: new (l , ir_leaves , HfPlusNode :: Union (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , }) , initial . ir_node . into_inner () . into () ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Singleton < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Singleton { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , U , W , C , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (Self :: other_ir_node (other)) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Singleton < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CrossSingleton (Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , Box :: new (HfPlusNode :: Unpersist (Box :: new (Self :: other_ir_node (other)))) ,))) ,) } } pub use crate :: singleton :: Optional ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Optional { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } pub fn some (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: new (singleton . location_kind , singleton . ir_leaves , singleton . ir_node . into_inner () ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > From < Singleton < 'a , T , W , C , N > > for Optional < 'a , T , W , C , N > { fn from (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: some (singleton) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Optional < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Optional { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn into_stream (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , Tick , N > > ,) -> Optional < 'a , (T , O) , Bounded , Tick , N > where O : Clone , { let other : Optional < 'a , O , Bounded , Tick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn union (self , other : Optional < 'a , T , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Optional < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_samples (self) -> Stream < 'a , T , Unbounded , NoTick , N > { self . latest_tick () . all_ticks () } pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . latest_tick () . continue_if (samples . first ()) . latest () . tick_samples () } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Unbounded , NoTick , N > > ,) -> Optional < 'a , (T , O) , Unbounded , NoTick , N > where O : Clone , { let other : Optional < 'a , O , Unbounded , NoTick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } self . latest_tick () . cross_singleton (other . latest_tick ()) . latest () } } } pub use singleton :: { Optional , Singleton } ; pub mod location { pub use std :: marker :: PhantomData ; pub use crate :: location :: LocationId ; pub use crate :: location :: Location ; pub use crate :: location :: Process ; # [cfg (stageleft_macro)] impl < P > Clone for Process < P > { fn clone (& self) -> Self { Process { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < P > Location for Process < P > { fn id (& self) -> LocationId { LocationId :: Process (self . id) } } pub use crate :: location :: Cluster ; # [cfg (stageleft_macro)] impl < C > Clone for Cluster < C > { fn clone (& self) -> Self { Cluster { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < C > Location for Cluster < C > { fn id (& self) -> LocationId { LocationId :: Cluster (self . id) } } pub use crate :: location :: CanSend ; # [cfg (stageleft_macro)] impl < P1 , P2 > CanSend < Process < P2 > > for Process < P1 > { type In < T > = T ; type Out < T > = T ; fn is_demux () -> bool { false } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < P1 , C2 > CanSend < Cluster < C2 > > for Process < P1 > { type In < T > = (u32 , T) ; type Out < T > = T ; fn is_demux () -> bool { true } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < C1 , P2 > CanSend < Process < P2 > > for Cluster < C1 > { type In < T > = T ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { false } fn is_tagged () -> bool { true } } # [cfg (stageleft_macro)] impl < C1 , C2 > CanSend < Cluster < C2 > > for Cluster < C1 > { type In < T > = (u32 , T) ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { true } fn is_tagged () -> bool { true } } } pub use location :: { Cluster , Process } ; pub mod deploy { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use stageleft :: Quoted ; pub mod graphs { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use super :: { LocalDeploy , Node , ProcessSpec } ; pub use crate :: deploy :: graphs :: SingleProcessGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for SingleProcessGraph { type Process = SingleNode ; type Cluster = SingleNode ; type Meta = () ; type GraphId = () ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { SingleNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { SingleNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , SingleProcessGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> SingleNode { SingleNode { } } } pub use crate :: deploy :: graphs :: SingleNode ; # [cfg (stageleft_macro)] impl Node for SingleNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } pub use crate :: deploy :: graphs :: MultiGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for MultiGraph { type Process = MultiNode ; type Cluster = MultiNode ; type Meta = () ; type GraphId = usize ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { MultiNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { MultiNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , MultiGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> MultiNode { MultiNode { } } } pub use crate :: deploy :: graphs :: MultiNode ; # [cfg (stageleft_macro)] impl Node for MultiNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } } pub use graphs :: * ; pub use crate :: deploy :: LocalDeploy ; pub use crate :: deploy :: Deploy ; # [cfg (stageleft_macro)] impl < 'a , T : Deploy < 'a , Process = N , Cluster = C , Meta = M , GraphId = R > , N : Node < Meta = M > , C : Node < Meta = M > , M : Default , R , > LocalDeploy < 'a > for T { type Process = N ; type Cluster = C ; type Meta = M ; type GraphId = R ; fn has_trivial_node () -> bool { < T as Deploy < 'a > > :: has_trivial_node () } fn trivial_process (id : usize) -> Self :: Process { < T as Deploy < 'a > > :: trivial_process (id) } fn trivial_cluster (id : usize) -> Self :: Cluster { < T as Deploy < 'a > > :: trivail_cluster (id) } } pub use crate :: deploy :: ProcessSpec ; pub use crate :: deploy :: ClusterSpec ; pub use crate :: deploy :: Node ; } pub use deploy :: { ClusterSpec , Deploy , ProcessSpec } ; pub mod cycle { pub use std :: marker :: PhantomData ; pub use crate :: builder :: FlowLeaves ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: cycle :: CycleComplete ; pub use crate :: cycle :: CycleCollection ; pub use crate :: cycle :: CycleCollectionWithInitial ; pub use crate :: cycle :: HfCycle ; # [cfg (stageleft_macro)] impl < 'a , S : CycleComplete < 'a > > HfCycle < 'a , S > { pub fn complete (self , stream : S) { let ident = self . ident ; S :: complete (stream , ident) } } } pub use cycle :: HfCycle ; pub mod builder { pub use std :: cell :: RefCell ; pub use std :: collections :: HashMap ; pub use std :: marker :: PhantomData ; pub use std :: rc :: Rc ; pub use std :: time :: Duration ; pub use hydroflow :: futures :: stream :: Stream as FuturesStream ; pub use hydroflow :: { tokio , tokio_stream } ; pub use internal :: TokenStream ; pub use proc_macro2 :: Span ; pub use quote :: quote ; pub use runtime_support :: FreeVariable ; pub use stageleft :: * ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Cluster , Location , LocationId , Process } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: { HfCycle , Optional , RuntimeContext , Singleton , Stream } ; pub mod built { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use hydroflow_lang :: graph :: { eliminate_extra_unions_tees , HydroflowGraph } ; pub use super :: deploy :: { DeployFlow , DeployResult } ; pub use crate :: deploy :: { ClusterSpec , Deploy , LocalDeploy , ProcessSpec } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Cluster , Process } ; pub use crate :: HfCompiled ; pub use crate :: builder :: built :: BuiltFlow ; # [cfg (stageleft_macro)] impl < 'a > Drop for BuiltFlow < 'a > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped BuiltFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn ir (& self) -> & Vec < HfPlusLeaf < 'a > > { & self . ir } pub fn optimize_with (mut self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> BuiltFlow < 'a > { self . used = true ; BuiltFlow { ir : f (std :: mem :: take (& mut self . ir)) , processes : std :: mem :: take (& mut self . processes) , clusters : std :: mem :: take (& mut self . clusters) , used : false , _phantom : PhantomData , } } } pub fn build_inner (ir : & mut Vec < HfPlusLeaf >) -> BTreeMap < usize , HydroflowGraph > { let mut builders = BTreeMap :: new () ; let mut built_tees = HashMap :: new () ; let mut next_stmt_id = 0 ; for leaf in ir { leaf . emit (& mut builders , & mut built_tees , & mut next_stmt_id) ; } builders . into_iter () . map (| (k , v) | { let (mut flat_graph , _ , _) = v . build () ; eliminate_extra_unions_tees (& mut flat_graph) ; (k , flat_graph) }) . collect () } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn compile_no_network < D : LocalDeploy < 'a > > (mut self) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; HfCompiled { hydroflow_ir : build_inner (& mut self . ir) , extra_stmts : BTreeMap :: new () , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> BuiltFlow < 'a > { self . optimize_with (crate :: persist_pullup :: persist_pullup) } fn into_deploy < D : LocalDeploy < 'a > > (mut self) -> DeployFlow < 'a , D > { self . used = true ; let processes = if D :: has_trivial_node () { self . processes . iter () . map (| id | (* id , D :: trivial_process (* id))) . collect () } else { HashMap :: new () } ; let clusters = if D :: has_trivial_node () { self . clusters . iter () . map (| id | (* id , D :: trivial_cluster (* id))) . collect () } else { HashMap :: new () } ; DeployFlow { ir : std :: mem :: take (& mut self . ir) , nodes : processes , clusters , used : false , _phantom : PhantomData , } } pub fn with_process < P , D : LocalDeploy < 'a > > (self , process : & Process < P > , spec : impl ProcessSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_process (process , spec) } pub fn with_cluster < C , D : LocalDeploy < 'a > > (self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_cluster (cluster , spec) } pub fn compile < D : Deploy < 'a > + 'a > (self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . into_deploy :: < D > () . compile (env) } pub fn deploy < D : Deploy < 'a , CompileEnv = () > + 'a > (self , env : & mut D :: InstantiateEnv ,) -> DeployResult < 'a , D > { self . into_deploy :: < D > () . deploy (env) } } } pub mod deploy { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use proc_macro2 :: Span ; pub use stageleft :: Quoted ; pub use super :: built :: build_inner ; pub use crate :: deploy :: { LocalDeploy , Node } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: { Cluster , ClusterSpec , Deploy , HfCompiled , Process , ProcessSpec } ; pub use crate :: builder :: deploy :: DeployFlow ; # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > Drop for DeployFlow < 'a , D > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped DeployFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > DeployFlow < 'a , D > { pub fn with_process < P > (mut self , process : & Process < P > , spec : impl ProcessSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < P > () . to_string () ; self . nodes . insert (process . id , spec . build (process . id , & tag_name)) ; self } pub fn with_cluster < C > (mut self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < C > () . to_string () ; self . clusters . insert (cluster . id , spec . build (cluster . id , & tag_name)) ; self } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployFlow < 'a , D > { pub fn compile (mut self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; let mut seen_tees : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | leaf . compile_network :: < D > (env , & mut seen_tees , & self . nodes , & self . clusters)) . collect () ; let extra_stmts = self . extra_stmts (env) ; HfCompiled { hydroflow_ir : build_inner (& mut ir_leaves_networked) , extra_stmts , _phantom : PhantomData , } } fn extra_stmts (& self , env : & < D as Deploy < 'a > > :: CompileEnv) -> BTreeMap < usize , Vec < syn :: Stmt > > { let all_locations_count = self . nodes . len () + self . clusters . len () ; let mut extra_stmts : BTreeMap < usize , Vec < syn :: Stmt > > = BTreeMap :: new () ; for & c_id in self . clusters . keys () { let self_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , c_id) , Span :: call_site () ,) ; let self_id_expr = D :: cluster_self_id (env) . splice () ; extra_stmts . entry (c_id) . or_default () . push (syn :: parse_quote ! { let # self_id_ident = # self_id_expr ; }) ; for other_location in 0 .. all_locations_count { let other_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , c_id) , Span :: call_site () ,) ; let other_id_expr = D :: cluster_ids (env , c_id) . splice () ; extra_stmts . entry (other_location) . or_default () . push (syn :: parse_quote ! { let # other_id_ident = # other_id_expr ; }) ; } } extra_stmts } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a , CompileEnv = () > > DeployFlow < 'a , D > { # [must_use] pub fn deploy (mut self , env : & mut D :: InstantiateEnv) -> DeployResult < 'a , D > { self . used = true ; let mut seen_tees_instantiate : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | { leaf . compile_network :: < D > (& () , & mut seen_tees_instantiate , & self . nodes , & self . clusters ,) }) . collect () ; let mut compiled = build_inner (& mut ir_leaves_networked) ; let mut extra_stmts = self . extra_stmts (& ()) ; let mut meta = D :: Meta :: default () ; let (mut processes , mut clusters) = (std :: mem :: take (& mut self . nodes) . into_iter () . map (| (node_id , node) | { node . instantiate (env , & mut meta , compiled . remove (& node_id) . unwrap () , extra_stmts . remove (& node_id) . unwrap_or_default () ,) ; (node_id , node) }) . collect :: < HashMap < _ , _ > > () , std :: mem :: take (& mut self . clusters) . into_iter () . map (| (cluster_id , cluster) | { cluster . instantiate (env , & mut meta , compiled . remove (& cluster_id) . unwrap () , extra_stmts . remove (& cluster_id) . unwrap_or_default () ,) ; (cluster_id , cluster) }) . collect :: < HashMap < _ , _ > > () ,) ; for node in processes . values_mut () { node . update_meta (& meta) ; } for cluster in clusters . values_mut () { cluster . update_meta (& meta) ; } let mut seen_tees_connect = HashMap :: new () ; for leaf in ir_leaves_networked { leaf . connect_network (& mut seen_tees_connect) ; } DeployResult { processes , clusters , } } } pub use crate :: builder :: deploy :: DeployResult ; # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployResult < 'a , D > { pub fn get_process < P > (& self , p : & Process < P >) -> & D :: Process { let id = match p . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . processes . get (& id) . unwrap () } pub fn get_cluster < C > (& self , c : & Cluster < C >) -> & D :: Cluster { let id = match c . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . clusters . get (& id) . unwrap () } } } # [doc = " Tracks the leaves of the dataflow IR. This is referenced by"] # [doc = " `Stream` and `HfCycle` to build the IR. The inner option will"] # [doc = " be set to `None` when this builder is finalized."] pub type FlowLeaves < 'a > = Rc < RefCell < Option < Vec < HfPlusLeaf < 'a > > > > > ; pub use crate :: builder :: ClusterIds ; # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Vec < u32 > > for ClusterIds < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , & 'a Vec < u32 > > for ClusterIds < 'a > { } # [derive (Copy , Clone)] pub struct ClusterSelfId < 'a > { pub id : usize , pub _phantom : PhantomData < & 'a mut & 'a u32 > , } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < u32 > for ClusterSelfId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , u32 > for ClusterSelfId < 'a > { } pub use crate :: builder :: FlowBuilder ; # [cfg (stageleft_macro)] impl < 'a > Drop for FlowBuilder < 'a > { fn drop (& mut self) { if ! self . finalized { panic ! ("Dropped FlowBuilder without finalizing, you may have forgotten to call `with_default_optimize`, `optimize_with`, or `finalize`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > QuotedContext for FlowBuilder < 'a > { fn create () -> Self { FlowBuilder :: new () } } # [cfg (stageleft_macro)] impl < 'a > FlowBuilder < 'a > { # [allow (clippy :: new_without_default)] pub fn new () -> FlowBuilder < 'a > { FlowBuilder { ir_leaves : Rc :: new (RefCell :: new (Some (Vec :: new ()))) , nodes : RefCell :: new (vec ! []) , clusters : RefCell :: new (vec ! []) , cycle_ids : RefCell :: new (HashMap :: new ()) , next_node_id : RefCell :: new (0) , finalized : false , _phantom : PhantomData , } } pub fn finalize (mut self) -> built :: BuiltFlow < 'a > { self . finalized = true ; built :: BuiltFlow { ir : self . ir_leaves . borrow_mut () . take () . unwrap () , processes : self . nodes . replace (vec ! []) , clusters : self . clusters . replace (vec ! []) , used : false , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> built :: BuiltFlow < 'a > { self . finalize () . with_default_optimize () } pub fn optimize_with (self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> built :: BuiltFlow < 'a > { self . finalize () . optimize_with (f) } pub fn ir_leaves (& self) -> & FlowLeaves < 'a > { & self . ir_leaves } pub fn process < P > (& self) -> Process < P > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . nodes . borrow_mut () . push (id) ; Process { id , _phantom : PhantomData , } } pub fn cluster < C > (& self) -> Cluster < C > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . clusters . borrow_mut () . push (id) ; Cluster { id , _phantom : PhantomData , } } pub fn runtime_context (& self) -> RuntimeContext < 'a > { RuntimeContext { _phantom : PhantomData , } } pub fn cluster_members < C > (& self , cluster : & Cluster < C > ,) -> impl Quoted < 'a , & 'a Vec < u32 > > + Copy + 'a { ClusterIds { id : cluster . id , _phantom : PhantomData , } } pub fn cluster_self_id < C > (& self , cluster : & Cluster < C >) -> impl Quoted < 'a , u32 > + Copy + 'a { ClusterSelfId { id : cluster . id , _phantom : PhantomData , } } pub fn spin < L : Location > (& self , on : & L) -> Stream < 'a , () , Unbounded , NoTick , L > { Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Spin () , location_kind : on . id () , })) ,) } pub fn spin_batch < L : Location > (& self , on : & L , batch_size : impl Quoted < 'a , usize > + Copy + 'a ,) -> Stream < 'a , () , Bounded , Tick , L > { self . spin (on) . flat_map (q ! (move | _ | 0 .. batch_size)) . map (q ! (| _ | ())) . tick_batch () } pub fn source_stream < T , E : FuturesStream < Item = T > + Unpin , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Unbounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Stream (e . into ()) , location_kind : on . id () , })) ,) } pub fn source_iter < T , E : IntoIterator < Item = T > , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Bounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , })) ,) } pub fn singleton < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Singleton < 'a , T , Bounded , NoTick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Singleton :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,)))) ,) } pub fn singleton_first_tick < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Optional < 'a , T , Bounded , Tick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,) } pub fn source_interval < L : Location > (& self , on : & L , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , () , Unbounded , NoTick , L > { let interval = interval . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : on . id () , })) ,) } pub fn source_interval_delayed < L : Location > (& self , on : & L , delay : impl Quoted < 'a , Duration > + Copy + 'a , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , tokio :: time :: Instant , Unbounded , NoTick , L > { self . source_stream (on , q ! (tokio_stream :: wrappers :: IntervalStream :: new (tokio :: time :: interval_at (tokio :: time :: Instant :: now () + delay , interval))) ,) . tick_batch () . first () . latest () } pub fn cycle < S : CycleCollection < 'a > > (& self , on : & S :: Location) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , on . id ()) ,) } pub fn cycle_with_initial < S : CycleCollectionWithInitial < 'a > > (& self , on : & S :: Location , initial : S ,) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , initial , on . id ()) ,) } } } pub use builder :: FlowBuilder ; pub mod ir { pub use core :: panic ; pub use std :: cell :: RefCell ; pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow_lang :: graph :: FlatGraphBuilder ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: ToTokens ; pub use syn :: parse_quote ; pub use crate :: deploy :: Deploy ; pub use crate :: location :: LocationId ; pub use crate :: ir :: DebugExpr ; # [cfg (stageleft_macro)] impl From < syn :: Expr > for DebugExpr { fn from (expr : syn :: Expr) -> DebugExpr { DebugExpr (expr) } } # [cfg (stageleft_macro)] impl Deref for DebugExpr { type Target = syn :: Expr ; fn deref (& self) -> & Self :: Target { & self . 0 } } # [cfg (stageleft_macro)] impl ToTokens for DebugExpr { fn to_tokens (& self , tokens : & mut TokenStream) { self . 0 . to_tokens (tokens) ; } } # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugExpr { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "{}" , self . 0 . to_token_stream ()) } } pub use crate :: ir :: DebugInstantiate ; # [cfg (stageleft_macro)] impl < 'a > std :: fmt :: Debug for DebugInstantiate < 'a > { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<network instantiate>") } } pub use crate :: ir :: DebugPipelineFn ; # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugPipelineFn { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<function>") } } pub use crate :: ir :: HfPlusSource ; pub use crate :: ir :: HfPlusLeaf ; # [cfg (stageleft_macro)] impl < 'a > HfPlusLeaf < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . compile_network :: < D > (compile_env , s , nodes , clusters) ; } , seen_tees ,) } pub fn connect_network (self , seen_tees : & mut SeenTees < 'a >) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . connect_network (s) ; } , seen_tees ,) } pub fn transform_children (self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) -> HfPlusLeaf < 'a > { match self { HfPlusLeaf :: ForEach { f , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: ForEach { f , input } } HfPlusLeaf :: DestSink { sink , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: DestSink { sink , input } } HfPlusLeaf :: CycleSink { ident , location_kind , mut input , } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: CycleSink { ident , location_kind , input , } } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) { match self { HfPlusLeaf :: ForEach { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> for_each (# f) ; }) ; } HfPlusLeaf :: DestSink { sink , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink) ; }) ; } HfPlusLeaf :: CycleSink { ident , location_kind , input , } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; assert_eq ! (input_location_id , * location_id , "cycle_sink location mismatch") ; graph_builders . entry (* location_id) . or_default () . add_statement (parse_quote ! { # ident = # input_ident ; }) ; } } } } pub use crate :: ir :: HfPlusNode ; pub type SeenTees < 'a > = HashMap < * const RefCell < HfPlusNode < 'a > > , Rc < RefCell < HfPlusNode < 'a > > > > ; # [cfg (stageleft_macro)] impl < 'a > HfPlusNode < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (& mut self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) { self . transform_children (| n , s | n . compile_network :: < D > (compile_env , s , nodes , clusters) , seen_tees ,) ; if let HfPlusNode :: Network { from_location , to_location , instantiate_fn , .. } = self { let (sink_expr , source_expr , connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { let ((sink , source) , connect_fn) = match (from_location , to_location) { (LocationId :: Process (from) , LocationId :: Process (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: o2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Process (from) , LocationId :: Cluster (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: o2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Process (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: m2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Cluster (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: m2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } } ; (sink , source , connect_fn) } DebugInstantiate :: Finalized (_ , _ , _) => panic ! ("network already finalized") , } ; * instantiate_fn = DebugInstantiate :: Finalized (sink_expr , source_expr , connect_fn) ; } } pub fn connect_network (& mut self , seen_tees : & mut SeenTees < 'a >) { self . transform_children (| n , s | n . connect_network (s) , seen_tees) ; if let HfPlusNode :: Network { instantiate_fn , .. } = self { match instantiate_fn { DebugInstantiate :: Building () => panic ! ("network not built") , DebugInstantiate :: Finalized (_ , _ , ref connect_fn) => { connect_fn () ; } } } } pub fn transform_children (& mut self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) { match self { HfPlusNode :: Placeholder => { panic ! () ; } HfPlusNode :: Source { .. } => { } HfPlusNode :: CycleSource { .. } => { } HfPlusNode :: Tee { inner } => { if let Some (transformed) = seen_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { * inner = transformed . clone () ; } else { let transformed_cell = Rc :: new (RefCell :: new (HfPlusNode :: Placeholder)) ; seen_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , transformed_cell . clone () ,) ; let mut orig = inner . replace (HfPlusNode :: Placeholder) ; transform (& mut orig , seen_tees) ; * transformed_cell . borrow_mut () = orig ; * inner = transformed_cell ; } } HfPlusNode :: Persist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Unpersist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Delta (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Union (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossProduct (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossSingleton (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Join (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Difference (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: AntiJoin (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Map { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FlatMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Filter { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FilterMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Sort (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: DeferTick (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Enumerate (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Inspect { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Unique (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Fold { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FoldKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Reduce { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: ReduceKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Network { input , .. } => { transform (input . as_mut () , seen_tees) ; } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) -> (syn :: Ident , usize) { match self { HfPlusNode :: Placeholder => { panic ! () } HfPlusNode :: Persist (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let persist_id = * next_stmt_id ; * next_stmt_id += 1 ; let persist_ident = syn :: Ident :: new (& format ! ("stream_{}" , persist_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # persist_ident = # inner_ident -> persist ::<'static > () ; }) ; (persist_ident , location) } HfPlusNode :: Unpersist (_) => { panic ! ("Unpersist is a marker node and should have been optimized away. This is likely a compiler bug.") } HfPlusNode :: Delta (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let delta_id = * next_stmt_id ; * next_stmt_id += 1 ; let delta_ident = syn :: Ident :: new (& format ! ("stream_{}" , delta_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # delta_ident = # inner_ident -> multiset_delta () ; }) ; (delta_ident , location) } HfPlusNode :: Source { source , location_kind , } => { let source_id = * next_stmt_id ; * next_stmt_id += 1 ; let source_ident = syn :: Ident :: new (& format ! ("stream_{}" , source_id) , Span :: call_site ()) ; let source_stmt = match source { HfPlusSource :: Stream (expr) => { parse_quote ! { # source_ident = source_stream (# expr) ; } } HfPlusSource :: Iter (expr) => { parse_quote ! { # source_ident = source_iter (# expr) ; } } HfPlusSource :: Interval (expr) => { parse_quote ! { # source_ident = source_interval (# expr) ; } } HfPlusSource :: Spin () => { parse_quote ! { # source_ident = spin () ; } } } ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; graph_builders . entry (* location_id) . or_default () . add_statement (source_stmt) ; (source_ident , * location_id) } HfPlusNode :: CycleSource { ident , location_kind , } => { let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; (ident . clone () , * location_id) } HfPlusNode :: Tee { inner } => { if let Some (ret) = built_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { ret . clone () } else { let (inner_ident , inner_location_id) = inner . borrow () . emit (graph_builders , built_tees , next_stmt_id) ; let tee_id = * next_stmt_id ; * next_stmt_id += 1 ; let tee_ident = syn :: Ident :: new (& format ! ("stream_{}" , tee_id) , Span :: call_site ()) ; let builder = graph_builders . entry (inner_location_id) . or_default () ; builder . add_statement (parse_quote ! { # tee_ident = # inner_ident -> tee () ; }) ; built_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , (tee_ident . clone () , inner_location_id) ,) ; (tee_ident , inner_location_id) } } HfPlusNode :: Union (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "union inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let union_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # union_ident = union () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [0] # union_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # union_ident ; }) ; (union_ident , left_location_id) } HfPlusNode :: CrossSingleton (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "cross_singleton inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let cross_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # cross_ident = cross_singleton () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [input] # cross_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [single] # cross_ident ; }) ; (cross_ident , left_location_id) } HfPlusNode :: CrossProduct (..) | HfPlusNode :: Join (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: CrossProduct (..)) { parse_quote ! (cross_join_multiset) } else { parse_quote ! (join_multiset) } ; let (HfPlusNode :: CrossProduct (left , right) | HfPlusNode :: Join (left , right)) = self else { unreachable ! () } ; let (left_inner , left_was_persist) = if let HfPlusNode :: Persist (left) = left . as_ref () { (left , true) } else { (left , false) } ; let (right_inner , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left_inner . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right_inner . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "join / cross product inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; match (left_was_persist , right_was_persist) { (true , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'static > () ; }) ; } (true , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'tick > () ; }) ; } (false , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } (false , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } } ; builder . add_statement (parse_quote ! { # left_ident -> [0] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Difference (..) | HfPlusNode :: AntiJoin (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Difference (..)) { parse_quote ! (difference_multiset) } else { parse_quote ! (anti_join_multiset) } ; let (HfPlusNode :: Difference (left , right) | HfPlusNode :: AntiJoin (left , right)) = self else { unreachable ! () } ; let (right , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "difference / anti join inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; if right_was_persist { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } else { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } builder . add_statement (parse_quote ! { # left_ident -> [pos] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [neg] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Map { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let map_id = * next_stmt_id ; * next_stmt_id += 1 ; let map_ident = syn :: Ident :: new (& format ! ("stream_{}" , map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # map_ident = # input_ident -> map (# f) ; }) ; (map_ident , input_location_id) } HfPlusNode :: FlatMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let flat_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let flat_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , flat_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # flat_map_ident = # input_ident -> flat_map (# f) ; }) ; (flat_map_ident , input_location_id) } HfPlusNode :: Filter { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_ident = # input_ident -> filter (# f) ; }) ; (filter_ident , input_location_id) } HfPlusNode :: FilterMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_map_ident = # input_ident -> filter_map (# f) ; }) ; (filter_map_ident , input_location_id) } HfPlusNode :: Sort (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sort_id = * next_stmt_id ; * next_stmt_id += 1 ; let sort_ident = syn :: Ident :: new (& format ! ("stream_{}" , sort_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # sort_ident = # input_ident -> sort () ; }) ; (sort_ident , input_location_id) } HfPlusNode :: DeferTick (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let defer_tick_id = * next_stmt_id ; * next_stmt_id += 1 ; let defer_tick_ident = syn :: Ident :: new (& format ! ("stream_{}" , defer_tick_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # defer_tick_ident = # input_ident -> defer_tick_lazy () ; }) ; (defer_tick_ident , input_location_id) } HfPlusNode :: Enumerate (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let enumerate_id = * next_stmt_id ; * next_stmt_id += 1 ; let enumerate_ident = syn :: Ident :: new (& format ! ("stream_{}" , enumerate_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # enumerate_ident = # input_ident -> enumerate () ; }) ; (enumerate_ident , input_location_id) } HfPlusNode :: Inspect { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let inspect_id = * next_stmt_id ; * next_stmt_id += 1 ; let inspect_ident = syn :: Ident :: new (& format ! ("stream_{}" , inspect_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # inspect_ident = # input_ident -> inspect (# f) ; }) ; (inspect_ident , input_location_id) } HfPlusNode :: Unique (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let unique_id = * next_stmt_id ; * next_stmt_id += 1 ; let unique_ident = syn :: Ident :: new (& format ! ("stream_{}" , unique_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # unique_ident = # input_ident -> unique ::<'tick > () ; }) ; (unique_ident , input_location_id) } HfPlusNode :: Fold { .. } | HfPlusNode :: FoldKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Fold { .. }) { parse_quote ! (fold) } else { parse_quote ! (fold_keyed) } ; let (HfPlusNode :: Fold { init , acc , input } | HfPlusNode :: FoldKeyed { init , acc , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let fold_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'static > (# init , # acc) ; }) ; } else { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'tick > (# init , # acc) ; }) ; } (fold_ident , input_location_id) } HfPlusNode :: Reduce { .. } | HfPlusNode :: ReduceKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Reduce { .. }) { parse_quote ! (reduce) } else { parse_quote ! (reduce_keyed) } ; let (HfPlusNode :: Reduce { f , input } | HfPlusNode :: ReduceKeyed { f , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let reduce_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'static > (# f) ; }) ; } else { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'tick > (# f) ; }) ; } (reduce_ident , input_location_id) } HfPlusNode :: Network { from_location : _ , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input , } => { let (sink_expr , source_expr , _connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { panic ! ("Expected the network to be finalized") } DebugInstantiate :: Finalized (sink , source , connect_fn) => { (sink , source , connect_fn) } } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sender_builder = graph_builders . entry (input_location_id) . or_default () ; if let Some (serialize_pipeline) = serialize_pipeline { sender_builder . add_statement (parse_quote ! { # input_ident -> # serialize_pipeline -> dest_sink (# sink_expr) ; }) ; } else { sender_builder . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink_expr) ; }) ; } let to_id = match to_location { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let receiver_builder = graph_builders . entry (* to_id) . or_default () ; let receiver_stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let receiver_stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , receiver_stream_id) , Span :: call_site ()) ; if let Some (deserialize_pipeline) = deserialize_pipeline { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) -> # deserialize_pipeline ; }) ; } else { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) ; }) ; } (receiver_stream_ident , * to_id) } } } } } pub mod persist_pullup { pub use std :: cell :: RefCell ; pub use std :: collections :: HashSet ; pub use std :: ops :: Deref ; pub use crate :: ir :: * ; pub fn persist_pullup_node < 'a > (node : & mut HfPlusNode < 'a > , seen_tees : & mut SeenTees < 'a > , persist_pulled_tees : & mut HashSet < * const RefCell < HfPlusNode < 'a > > > ,) { node . transform_children (| n , s | persist_pullup_node (n , s , persist_pulled_tees) , seen_tees ,) ; match node { HfPlusNode :: Unpersist (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Unpersist (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Delta (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Delta (box HfPlusNode :: Persist (deref!(behind_persist))) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Tee { inner } => { if persist_pulled_tees . contains (& (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >)) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } else { let inner_borrow = inner . borrow () ; if let HfPlusNode :: Persist (_) = inner_borrow . deref () { drop (inner_borrow) ; persist_pulled_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >) ; if let HfPlusNode :: Persist (box behind_persist) = inner . replace (HfPlusNode :: Placeholder) { * inner . borrow_mut () = behind_persist ; } else { unreachable ! () } * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } } } HfPlusNode :: Map { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Map { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Map { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: FlatMap { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: FlatMap { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: FlatMap { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Filter { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Filter { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Filter { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Network { input : box HfPlusNode :: Persist (_) , .. } => { if let HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Union (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Union (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Union (left , right))) ; } else { unreachable ! () } } HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: CrossProduct (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,) ,)))) ; } else { unreachable ! () } } HfPlusNode :: Join (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Join (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: Join (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,))))) ; } else { unreachable ! () } } _ => { } } } pub fn persist_pullup (ir : Vec < HfPlusLeaf >) -> Vec < HfPlusLeaf > { let mut seen_tees = Default :: default () ; let mut persist_pulled_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| n , s | persist_pullup_node (n , s , & mut persist_pulled_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn persist_pullup_through_map () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } # [test] fn persist_pullup_behind_tee () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; let before_tee = flow . source_iter (& process , q ! (0 .. 10)) . tick_batch () . persist () ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } } } pub mod profiler { pub use std :: cell :: RefCell ; pub use hydroflow :: futures :: channel :: mpsc :: UnboundedSender ; pub use stageleft :: * ; pub use crate as hydroflow_plus ; pub use crate :: ir :: * ; pub use crate :: RuntimeContext ; pub fn increment_counter (count : & mut u64) { * count += 1 ; } pub fn quoted_any_fn < 'a , F : Fn (& usize) + 'a , Q : IntoQuotedMut < 'a , F > > (q : Q) -> Q { q } # [doc = " Add a profiling node before each node to count the cardinality of its input"] pub fn add_profiling_node < 'a > (node : & mut HfPlusNode < 'a > , _context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > , id : & mut u32 , seen_tees : & mut SeenTees < 'a > ,) { let my_id = * id ; * id += 1 ; node . transform_children (| node , seen_tees | { add_profiling_node (node , _context , counters , counter_queue , id , seen_tees) } , seen_tees ,) ; let orig_node = std :: mem :: replace (node , HfPlusNode :: Placeholder) ; * node = HfPlusNode :: Inspect { f : quoted_any_fn (q ! ({ counter_queue . borrow () . unbounded_send ((my_id as usize , counters . borrow () [my_id as usize])) . unwrap () ; counters . borrow_mut () [my_id as usize] = 0 ; move | _ | { hydroflow_plus :: profiler :: increment_counter (& mut counters . borrow_mut () [my_id as usize] ,) ; } })) . splice () . into () , input : Box :: new (orig_node) , } } # [doc = " Count the cardinality of each input and periodically output to a file"] pub fn profiling < 'a > (ir : Vec < HfPlusLeaf < 'a > > , context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > ,) -> Vec < HfPlusLeaf < 'a > > { let mut id = 0 ; let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | { add_profiling_node (node , context , counters , counter_queue , & mut id , seen_tees) } , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn profiler_wrapping_all_operators () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let runtime_context = flow . runtime_context () ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (& built . ir ()) ; let counters = RuntimeData :: new ("Fake") ; let counter_queue = RuntimeData :: new ("Fake") ; let pushed_down = built . with_default_optimize () . optimize_with (| ir | super :: profiling (ir , runtime_context , counters , counter_queue)) ; insta :: assert_debug_snapshot ! (& pushed_down . ir ()) ; let _ = pushed_down . compile_no_network :: < MultiGraph > () ; } } } pub mod properties { pub use std :: collections :: HashSet ; pub use stageleft :: * ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , SeenTees } ; pub use crate :: properties :: PropertyDatabase ; # [doc = " Allows us to convert the hydroflow datatype for folds to a binary operation for the algebra"] # [doc = " property tests."] # [allow (dead_code)] pub fn convert_hf_to_binary < I , A : Default , F : Fn (& mut A , I) > (f : F) -> impl Fn (I , I) -> A { move | a , b | { let mut acc = Default :: default () ; f (& mut acc , a) ; f (& mut acc , b) ; acc } } # [cfg (stageleft_macro)] impl PropertyDatabase { # [doc = " Tags the expression as commutative."] pub fn add_commutative_tag < 'a , I , A , F : Fn (& mut A , I) , Q : Quoted < 'a , F > + Clone > (& mut self , expr : Q ,) -> Q { let expr_clone = expr . clone () ; self . commutative . insert (expr_clone . splice ()) ; expr } pub fn is_tagged_commutative (& self , expr : & syn :: Expr) -> bool { self . commutative . contains (expr) } } pub fn properties_optimize_node < 'a > (node : & mut HfPlusNode < 'a > , db : & PropertyDatabase , seen_tees : & mut SeenTees < 'a > ,) { node . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , seen_tees ,) ; match node { HfPlusNode :: ReduceKeyed { f , .. } if db . is_tagged_commutative (& f . 0) => { dbg ! ("IDENTIFIED COMMUTATIVE OPTIMIZATION for {:?}" , & f) ; } _ => { } } } pub fn properties_optimize < 'a > (ir : Vec < HfPlusLeaf < 'a > > , db : & PropertyDatabase ,) -> Vec < HfPlusLeaf < 'a > > { let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use super :: * ; use crate :: deploy :: SingleProcessGraph ; use crate :: FlowBuilder ; # [test] fn test_property_database () { let mut db = PropertyDatabase :: default () ; assert ! (! db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; let _ = db . add_commutative_tag (q ! (| a : & mut i32 , b : i32 | * a += b)) ; assert ! (db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; } # [test] fn test_property_optimized () { let flow = FlowBuilder :: new () ; let mut database = PropertyDatabase :: default () ; let process = flow . process :: < () > () ; let counter_func = q ! (| count : & mut i32 , _ | * count += 1) ; let _ = database . add_commutative_tag (counter_func) ; flow . source_iter (& process , q ! (vec ! [])) . map (q ! (| string : String | (string , ()))) . tick_batch () . fold_keyed (q ! (|| 0) , counter_func) . all_ticks () . for_each (q ! (| (string , count) | println ! ("{}: {}" , string , count))) ; let built = flow . finalize () . optimize_with (| ir | properties_optimize (ir , & database)) . with_default_optimize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let _ = built . compile_no_network :: < SingleProcessGraph > () ; } } } pub use crate :: RuntimeContext ; # [cfg (stageleft_macro)] impl Copy for RuntimeContext < '_ > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Context > for RuntimeContext < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (quote ! (& context))) } } pub use crate :: HfCompiled ; # [cfg (stageleft_macro)] impl < 'a , ID > HfCompiled < 'a , ID > { pub fn hydroflow_ir (& self) -> & BTreeMap < usize , HydroflowGraph > { & self . hydroflow_ir } } # [cfg (stageleft_macro)] impl < 'a > HfCompiled < 'a , usize > { pub fn with_dynamic_id (self , id : impl Quoted < 'a , usize >) -> HfBuiltWithId < 'a > { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; let mut conditioned_tokens = None ; for (subgraph_id , flat_graph) in self . hydroflow_ir { let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; let my_extra_stmts = self . extra_stmts . get (& subgraph_id) . cloned () . unwrap_or_default () ; if let Some (conditioned_tokens) = conditioned_tokens . as_mut () { * conditioned_tokens = syn :: parse_quote ! { # conditioned_tokens else if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } } ; } else { conditioned_tokens = Some (syn :: parse_quote ! { if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } }) ; } } let conditioned_tokens : TokenStream = conditioned_tokens . unwrap () ; let id = id . splice () ; HfBuiltWithId { tokens : syn :: parse_quote ! ({ let __given_id = # id ; # conditioned_tokens else { panic ! ("Invalid node id: {}" , __given_id) ; } }) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfCompiled < 'a , () > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfCompiled < 'a , () > { fn to_tokens (mut self) -> (Option < TokenStream > , Option < TokenStream >) { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; if self . hydroflow_ir . len () != 1 { panic ! ("Expected exactly one subgraph in the Hydroflow IR") ; } let flat_graph = self . hydroflow_ir . remove (& 0) . unwrap () ; let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; (None , Some (tokens)) } } pub use crate :: HfBuiltWithId ; # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfBuiltWithId < 'a > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfBuiltWithId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (self . tokens)) } }
[INFO] [stdout]   |
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] error: `box` patterns have been removed (feature `box_patterns`)
[INFO] [stdout]  --> /opt/rustwide/target/debug/build/hydroflow_plus/5672655b657d1e44/out/lib_pub.rs:1:92101
[INFO] [stdout]   |
[INFO] [stdout] 1 | ...ox HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Delta (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: rep...
[INFO] [stdout]   |                                                                   ^^^
[INFO] [stdout]   |
[INFO] [stdout]   = help: enable feature `deref_patterns` instead and...
[INFO] [stdout] help: ...if possible just remove keyword `box`...
[INFO] [stdout]   |
[INFO] [stdout] 1 - pub use std :: collections :: BTreeMap ; pub use std :: marker :: PhantomData ; pub use hydroflow :: scheduled :: context :: Context ; pub use hydroflow :: scheduled :: graph :: Hydroflow ; pub use hydroflow :: * ; pub use lang :: graph :: { partition_graph , HydroflowGraph } ; pub use proc_macro2 :: TokenStream ; pub use quote :: quote ; pub use stageleft :: runtime_support :: FreeVariable ; pub use stageleft :: Quoted ; pub mod runtime_support { pub use bincode ; } pub mod stream { pub use std :: cell :: RefCell ; pub use std :: hash :: Hash ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow :: bytes :: Bytes ; pub use hydroflow :: futures :: Sink ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: quote ; pub use serde :: de :: DeserializeOwned ; pub use serde :: Serialize ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use syn :: parse_quote ; pub use crate :: builder :: { ClusterIds , FlowLeaves } ; pub use crate :: cycle :: { CycleCollection , CycleComplete } ; pub use crate :: ir :: { DebugInstantiate , HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { CanSend , Location , LocationId } ; pub use crate :: { Cluster , Optional , Singleton } ; pub use crate :: stream :: Unbounded ; pub use crate :: stream :: Bounded ; pub use crate :: stream :: NoTick ; pub use crate :: stream :: Tick ; pub use crate :: stream :: Stream ; # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Stream { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Stream < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Stream { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , C , N > > ,) -> Stream < 'a , (T , O) , W , C , N > where O : Clone , { let other : Optional < 'a , O , Bounded , C , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn cross_product < O > (self , other : Stream < 'a , O , W , C , N >) -> Stream < 'a , (T , O) , W , C , N > where T : Clone , O : Clone , { if self . location_kind != other . location_kind { panic ! ("cross_product must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossProduct (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn union (self , other : Stream < 'a , T , W , C , N >) -> Stream < 'a , T , W , C , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn dest_sink < S : Unpin + Sink < T > + 'a > (self , sink : impl Quoted < 'a , S >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: DestSink { sink : sink . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn first (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } # [doc = " Allow this stream through if the other stream has elements, otherwise the output is empty."] pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } # [doc = " Allow this stream through if the other stream is empty, otherwise the output is empty."] pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn enumerate (self) -> Stream < 'a , (usize , T) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Enumerate (Box :: new (self . ir_node . into_inner ())) ,) } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn sort (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Ord , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Sort (Box :: new (self . ir_node . into_inner ())) ,) } pub fn count (self) -> Singleton < 'a , usize , Bounded , Tick , N > { self . fold (q ! (|| 0usize) , q ! (| count , _ | * count += 1)) } pub fn delta (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } pub fn unique (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Eq + Hash , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unique (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn tick_batch (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_prefix (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { self . tick_batch () . persist () } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn for_each < F : Fn (T) + 'a > (self , f : impl IntoQuotedMut < 'a , F >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: ForEach { input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , f : f . splice () . into () , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Unbounded , NoTick , N > { pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . tick_batch () . continue_if (samples . first ()) . all_ticks () } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Unbounded , NoTick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , C , N : Location > Stream < 'a , T , Bounded , C , N > { pub fn filter_not_in (self , other : Stream < 'a , T , Bounded , C , N >) -> Stream < 'a , T , Bounded , C , N > where T : Eq + Hash , { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Difference (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Stream < 'a , & T , W , C , N > { pub fn cloned (self) -> Stream < 'a , T , W , C , N > { self . map (q ! (| d | d . clone ())) } } # [cfg (stageleft_macro)] impl < 'a , K , V1 , W , C , N : Location > Stream < 'a , (K , V1) , W , C , N > { pub fn join < W2 , V2 > (self , n : Stream < 'a , (K , V2) , W2 , C , N > ,) -> Stream < 'a , (K , (V1 , V2)) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Join (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } pub fn anti_join < W2 > (self , n : Stream < 'a , K , W2 , C , N >) -> Stream < 'a , (K , V1) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("anti_join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: AntiJoin (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , K : Eq + Hash , V , N : Location > Stream < 'a , (K , V) , Bounded , Tick , N > { pub fn fold_keyed < A , I : Fn () -> A + 'a , F : Fn (& mut A , V) + 'a > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , A) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FoldKeyed { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce_keyed < F : Fn (& mut V , V) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , V) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: ReduceKeyed { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } pub fn get_this_crate () -> TokenStream { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , Span :: call_site ()) ; quote ! { # ident } } } } pub fn serialize_bincode < T : Serialize > (is_demux : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if is_demux { parse_quote ! { map (| (id , data) | { (id , # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into ()) }) } } else { parse_quote ! { map (| data | { # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into () }) } } } pub fn deserialize_bincode < T : DeserializeOwned > (tagged : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if tagged { parse_quote ! { map (| res | { let (id , b) = res . unwrap () ; (id , # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& b) . unwrap ()) }) } } else { parse_quote ! { map (| res | { # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& res . unwrap ()) . unwrap () }) } } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn send_bincode < N2 : Location , CoreType > (self , other : & N2 ,) -> Stream < 'a , N :: Out < CoreType > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T > , CoreType : Serialize + DeserializeOwned , { let serialize_pipeline = Some (serialize_bincode :: < CoreType > (N :: is_demux ())) ; let deserialize_pipeline = Some (deserialize_bincode :: < CoreType > (N :: is_tagged ())) ; Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bytes < N2 : Location > (self , other : & N2 ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T > , { Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline : None , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline : if N :: is_tagged () { Some (parse_quote ! (map (| (id , b) | (id , b . unwrap () . freeze ())))) } else { Some (parse_quote ! (map (| b | b . unwrap () . freeze ()))) } , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bincode_interleaved < N2 : Location , Tag , CoreType > (self , other : & N2 ,) -> Stream < 'a , CoreType , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T , Out < CoreType > = (Tag , CoreType) > , CoreType : Serialize + DeserializeOwned , { self . send_bincode :: < N2 , CoreType > (other) . map (q ! (| (_ , b) | b)) } pub fn send_bytes_interleaved < N2 : Location , Tag > (self , other : & N2 ,) -> Stream < 'a , Bytes , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T , Out < Bytes > = (Tag , Bytes) > , { self . send_bytes :: < N2 > (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bincode < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < T > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) > , T : Clone + Serialize + DeserializeOwned , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bincode (other) } pub fn broadcast_bincode_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , T , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) , Out < T > = (Tag , T) > + 'a , T : Clone + Serialize + DeserializeOwned , { self . broadcast_bincode (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bytes < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) > + 'a , T : Clone , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bytes (other) } pub fn broadcast_bytes_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , Bytes , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) , Out < Bytes > = (Tag , Bytes) > + 'a , T : Clone , { self . broadcast_bytes (other) . map (q ! (| (_ , b) | b)) } } } pub use stream :: { Bounded , NoTick , Stream , Tick , Unbounded } ; pub mod singleton { pub use std :: cell :: RefCell ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use crate :: builder :: FlowLeaves ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial , CycleComplete } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: Stream ; pub use crate :: singleton :: CrossResult ; # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Singleton < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Singleton :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } pub use crate :: singleton :: Singleton ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Singleton { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleComplete < 'a > for Singleton < 'a , T , Bounded , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleCollectionWithInitial < 'a > for Singleton < 'a , T , Bounded , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , initial : Self , l : LocationId ,) -> Self { Singleton :: new (l , ir_leaves , HfPlusNode :: Union (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , }) , initial . ir_node . into_inner () . into () ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Singleton < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Singleton { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , U , W , C , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (Self :: other_ir_node (other)) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Singleton < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CrossSingleton (Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , Box :: new (HfPlusNode :: Unpersist (Box :: new (Self :: other_ir_node (other)))) ,))) ,) } } pub use crate :: singleton :: Optional ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Optional { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } pub fn some (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: new (singleton . location_kind , singleton . ir_leaves , singleton . ir_node . into_inner () ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > From < Singleton < 'a , T , W , C , N > > for Optional < 'a , T , W , C , N > { fn from (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: some (singleton) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Optional < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Optional { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn into_stream (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , Tick , N > > ,) -> Optional < 'a , (T , O) , Bounded , Tick , N > where O : Clone , { let other : Optional < 'a , O , Bounded , Tick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn union (self , other : Optional < 'a , T , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Optional < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_samples (self) -> Stream < 'a , T , Unbounded , NoTick , N > { self . latest_tick () . all_ticks () } pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . latest_tick () . continue_if (samples . first ()) . latest () . tick_samples () } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Unbounded , NoTick , N > > ,) -> Optional < 'a , (T , O) , Unbounded , NoTick , N > where O : Clone , { let other : Optional < 'a , O , Unbounded , NoTick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } self . latest_tick () . cross_singleton (other . latest_tick ()) . latest () } } } pub use singleton :: { Optional , Singleton } ; pub mod location { pub use std :: marker :: PhantomData ; pub use crate :: location :: LocationId ; pub use crate :: location :: Location ; pub use crate :: location :: Process ; # [cfg (stageleft_macro)] impl < P > Clone for Process < P > { fn clone (& self) -> Self { Process { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < P > Location for Process < P > { fn id (& self) -> LocationId { LocationId :: Process (self . id) } } pub use crate :: location :: Cluster ; # [cfg (stageleft_macro)] impl < C > Clone for Cluster < C > { fn clone (& self) -> Self { Cluster { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < C > Location for Cluster < C > { fn id (& self) -> LocationId { LocationId :: Cluster (self . id) } } pub use crate :: location :: CanSend ; # [cfg (stageleft_macro)] impl < P1 , P2 > CanSend < Process < P2 > > for Process < P1 > { type In < T > = T ; type Out < T > = T ; fn is_demux () -> bool { false } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < P1 , C2 > CanSend < Cluster < C2 > > for Process < P1 > { type In < T > = (u32 , T) ; type Out < T > = T ; fn is_demux () -> bool { true } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < C1 , P2 > CanSend < Process < P2 > > for Cluster < C1 > { type In < T > = T ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { false } fn is_tagged () -> bool { true } } # [cfg (stageleft_macro)] impl < C1 , C2 > CanSend < Cluster < C2 > > for Cluster < C1 > { type In < T > = (u32 , T) ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { true } fn is_tagged () -> bool { true } } } pub use location :: { Cluster , Process } ; pub mod deploy { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use stageleft :: Quoted ; pub mod graphs { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use super :: { LocalDeploy , Node , ProcessSpec } ; pub use crate :: deploy :: graphs :: SingleProcessGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for SingleProcessGraph { type Process = SingleNode ; type Cluster = SingleNode ; type Meta = () ; type GraphId = () ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { SingleNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { SingleNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , SingleProcessGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> SingleNode { SingleNode { } } } pub use crate :: deploy :: graphs :: SingleNode ; # [cfg (stageleft_macro)] impl Node for SingleNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } pub use crate :: deploy :: graphs :: MultiGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for MultiGraph { type Process = MultiNode ; type Cluster = MultiNode ; type Meta = () ; type GraphId = usize ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { MultiNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { MultiNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , MultiGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> MultiNode { MultiNode { } } } pub use crate :: deploy :: graphs :: MultiNode ; # [cfg (stageleft_macro)] impl Node for MultiNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } } pub use graphs :: * ; pub use crate :: deploy :: LocalDeploy ; pub use crate :: deploy :: Deploy ; # [cfg (stageleft_macro)] impl < 'a , T : Deploy < 'a , Process = N , Cluster = C , Meta = M , GraphId = R > , N : Node < Meta = M > , C : Node < Meta = M > , M : Default , R , > LocalDeploy < 'a > for T { type Process = N ; type Cluster = C ; type Meta = M ; type GraphId = R ; fn has_trivial_node () -> bool { < T as Deploy < 'a > > :: has_trivial_node () } fn trivial_process (id : usize) -> Self :: Process { < T as Deploy < 'a > > :: trivial_process (id) } fn trivial_cluster (id : usize) -> Self :: Cluster { < T as Deploy < 'a > > :: trivail_cluster (id) } } pub use crate :: deploy :: ProcessSpec ; pub use crate :: deploy :: ClusterSpec ; pub use crate :: deploy :: Node ; } pub use deploy :: { ClusterSpec , Deploy , ProcessSpec } ; pub mod cycle { pub use std :: marker :: PhantomData ; pub use crate :: builder :: FlowLeaves ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: cycle :: CycleComplete ; pub use crate :: cycle :: CycleCollection ; pub use crate :: cycle :: CycleCollectionWithInitial ; pub use crate :: cycle :: HfCycle ; # [cfg (stageleft_macro)] impl < 'a , S : CycleComplete < 'a > > HfCycle < 'a , S > { pub fn complete (self , stream : S) { let ident = self . ident ; S :: complete (stream , ident) } } } pub use cycle :: HfCycle ; pub mod builder { pub use std :: cell :: RefCell ; pub use std :: collections :: HashMap ; pub use std :: marker :: PhantomData ; pub use std :: rc :: Rc ; pub use std :: time :: Duration ; pub use hydroflow :: futures :: stream :: Stream as FuturesStream ; pub use hydroflow :: { tokio , tokio_stream } ; pub use internal :: TokenStream ; pub use proc_macro2 :: Span ; pub use quote :: quote ; pub use runtime_support :: FreeVariable ; pub use stageleft :: * ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Cluster , Location , LocationId , Process } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: { HfCycle , Optional , RuntimeContext , Singleton , Stream } ; pub mod built { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use hydroflow_lang :: graph :: { eliminate_extra_unions_tees , HydroflowGraph } ; pub use super :: deploy :: { DeployFlow , DeployResult } ; pub use crate :: deploy :: { ClusterSpec , Deploy , LocalDeploy , ProcessSpec } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Cluster , Process } ; pub use crate :: HfCompiled ; pub use crate :: builder :: built :: BuiltFlow ; # [cfg (stageleft_macro)] impl < 'a > Drop for BuiltFlow < 'a > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped BuiltFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn ir (& self) -> & Vec < HfPlusLeaf < 'a > > { & self . ir } pub fn optimize_with (mut self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> BuiltFlow < 'a > { self . used = true ; BuiltFlow { ir : f (std :: mem :: take (& mut self . ir)) , processes : std :: mem :: take (& mut self . processes) , clusters : std :: mem :: take (& mut self . clusters) , used : false , _phantom : PhantomData , } } } pub fn build_inner (ir : & mut Vec < HfPlusLeaf >) -> BTreeMap < usize , HydroflowGraph > { let mut builders = BTreeMap :: new () ; let mut built_tees = HashMap :: new () ; let mut next_stmt_id = 0 ; for leaf in ir { leaf . emit (& mut builders , & mut built_tees , & mut next_stmt_id) ; } builders . into_iter () . map (| (k , v) | { let (mut flat_graph , _ , _) = v . build () ; eliminate_extra_unions_tees (& mut flat_graph) ; (k , flat_graph) }) . collect () } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn compile_no_network < D : LocalDeploy < 'a > > (mut self) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; HfCompiled { hydroflow_ir : build_inner (& mut self . ir) , extra_stmts : BTreeMap :: new () , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> BuiltFlow < 'a > { self . optimize_with (crate :: persist_pullup :: persist_pullup) } fn into_deploy < D : LocalDeploy < 'a > > (mut self) -> DeployFlow < 'a , D > { self . used = true ; let processes = if D :: has_trivial_node () { self . processes . iter () . map (| id | (* id , D :: trivial_process (* id))) . collect () } else { HashMap :: new () } ; let clusters = if D :: has_trivial_node () { self . clusters . iter () . map (| id | (* id , D :: trivial_cluster (* id))) . collect () } else { HashMap :: new () } ; DeployFlow { ir : std :: mem :: take (& mut self . ir) , nodes : processes , clusters , used : false , _phantom : PhantomData , } } pub fn with_process < P , D : LocalDeploy < 'a > > (self , process : & Process < P > , spec : impl ProcessSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_process (process , spec) } pub fn with_cluster < C , D : LocalDeploy < 'a > > (self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_cluster (cluster , spec) } pub fn compile < D : Deploy < 'a > + 'a > (self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . into_deploy :: < D > () . compile (env) } pub fn deploy < D : Deploy < 'a , CompileEnv = () > + 'a > (self , env : & mut D :: InstantiateEnv ,) -> DeployResult < 'a , D > { self . into_deploy :: < D > () . deploy (env) } } } pub mod deploy { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use proc_macro2 :: Span ; pub use stageleft :: Quoted ; pub use super :: built :: build_inner ; pub use crate :: deploy :: { LocalDeploy , Node } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: { Cluster , ClusterSpec , Deploy , HfCompiled , Process , ProcessSpec } ; pub use crate :: builder :: deploy :: DeployFlow ; # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > Drop for DeployFlow < 'a , D > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped DeployFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > DeployFlow < 'a , D > { pub fn with_process < P > (mut self , process : & Process < P > , spec : impl ProcessSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < P > () . to_string () ; self . nodes . insert (process . id , spec . build (process . id , & tag_name)) ; self } pub fn with_cluster < C > (mut self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < C > () . to_string () ; self . clusters . insert (cluster . id , spec . build (cluster . id , & tag_name)) ; self } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployFlow < 'a , D > { pub fn compile (mut self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; let mut seen_tees : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | leaf . compile_network :: < D > (env , & mut seen_tees , & self . nodes , & self . clusters)) . collect () ; let extra_stmts = self . extra_stmts (env) ; HfCompiled { hydroflow_ir : build_inner (& mut ir_leaves_networked) , extra_stmts , _phantom : PhantomData , } } fn extra_stmts (& self , env : & < D as Deploy < 'a > > :: CompileEnv) -> BTreeMap < usize , Vec < syn :: Stmt > > { let all_locations_count = self . nodes . len () + self . clusters . len () ; let mut extra_stmts : BTreeMap < usize , Vec < syn :: Stmt > > = BTreeMap :: new () ; for & c_id in self . clusters . keys () { let self_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , c_id) , Span :: call_site () ,) ; let self_id_expr = D :: cluster_self_id (env) . splice () ; extra_stmts . entry (c_id) . or_default () . push (syn :: parse_quote ! { let # self_id_ident = # self_id_expr ; }) ; for other_location in 0 .. all_locations_count { let other_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , c_id) , Span :: call_site () ,) ; let other_id_expr = D :: cluster_ids (env , c_id) . splice () ; extra_stmts . entry (other_location) . or_default () . push (syn :: parse_quote ! { let # other_id_ident = # other_id_expr ; }) ; } } extra_stmts } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a , CompileEnv = () > > DeployFlow < 'a , D > { # [must_use] pub fn deploy (mut self , env : & mut D :: InstantiateEnv) -> DeployResult < 'a , D > { self . used = true ; let mut seen_tees_instantiate : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | { leaf . compile_network :: < D > (& () , & mut seen_tees_instantiate , & self . nodes , & self . clusters ,) }) . collect () ; let mut compiled = build_inner (& mut ir_leaves_networked) ; let mut extra_stmts = self . extra_stmts (& ()) ; let mut meta = D :: Meta :: default () ; let (mut processes , mut clusters) = (std :: mem :: take (& mut self . nodes) . into_iter () . map (| (node_id , node) | { node . instantiate (env , & mut meta , compiled . remove (& node_id) . unwrap () , extra_stmts . remove (& node_id) . unwrap_or_default () ,) ; (node_id , node) }) . collect :: < HashMap < _ , _ > > () , std :: mem :: take (& mut self . clusters) . into_iter () . map (| (cluster_id , cluster) | { cluster . instantiate (env , & mut meta , compiled . remove (& cluster_id) . unwrap () , extra_stmts . remove (& cluster_id) . unwrap_or_default () ,) ; (cluster_id , cluster) }) . collect :: < HashMap < _ , _ > > () ,) ; for node in processes . values_mut () { node . update_meta (& meta) ; } for cluster in clusters . values_mut () { cluster . update_meta (& meta) ; } let mut seen_tees_connect = HashMap :: new () ; for leaf in ir_leaves_networked { leaf . connect_network (& mut seen_tees_connect) ; } DeployResult { processes , clusters , } } } pub use crate :: builder :: deploy :: DeployResult ; # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployResult < 'a , D > { pub fn get_process < P > (& self , p : & Process < P >) -> & D :: Process { let id = match p . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . processes . get (& id) . unwrap () } pub fn get_cluster < C > (& self , c : & Cluster < C >) -> & D :: Cluster { let id = match c . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . clusters . get (& id) . unwrap () } } } # [doc = " Tracks the leaves of the dataflow IR. This is referenced by"] # [doc = " `Stream` and `HfCycle` to build the IR. The inner option will"] # [doc = " be set to `None` when this builder is finalized."] pub type FlowLeaves < 'a > = Rc < RefCell < Option < Vec < HfPlusLeaf < 'a > > > > > ; pub use crate :: builder :: ClusterIds ; # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Vec < u32 > > for ClusterIds < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , & 'a Vec < u32 > > for ClusterIds < 'a > { } # [derive (Copy , Clone)] pub struct ClusterSelfId < 'a > { pub id : usize , pub _phantom : PhantomData < & 'a mut & 'a u32 > , } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < u32 > for ClusterSelfId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , u32 > for ClusterSelfId < 'a > { } pub use crate :: builder :: FlowBuilder ; # [cfg (stageleft_macro)] impl < 'a > Drop for FlowBuilder < 'a > { fn drop (& mut self) { if ! self . finalized { panic ! ("Dropped FlowBuilder without finalizing, you may have forgotten to call `with_default_optimize`, `optimize_with`, or `finalize`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > QuotedContext for FlowBuilder < 'a > { fn create () -> Self { FlowBuilder :: new () } } # [cfg (stageleft_macro)] impl < 'a > FlowBuilder < 'a > { # [allow (clippy :: new_without_default)] pub fn new () -> FlowBuilder < 'a > { FlowBuilder { ir_leaves : Rc :: new (RefCell :: new (Some (Vec :: new ()))) , nodes : RefCell :: new (vec ! []) , clusters : RefCell :: new (vec ! []) , cycle_ids : RefCell :: new (HashMap :: new ()) , next_node_id : RefCell :: new (0) , finalized : false , _phantom : PhantomData , } } pub fn finalize (mut self) -> built :: BuiltFlow < 'a > { self . finalized = true ; built :: BuiltFlow { ir : self . ir_leaves . borrow_mut () . take () . unwrap () , processes : self . nodes . replace (vec ! []) , clusters : self . clusters . replace (vec ! []) , used : false , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> built :: BuiltFlow < 'a > { self . finalize () . with_default_optimize () } pub fn optimize_with (self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> built :: BuiltFlow < 'a > { self . finalize () . optimize_with (f) } pub fn ir_leaves (& self) -> & FlowLeaves < 'a > { & self . ir_leaves } pub fn process < P > (& self) -> Process < P > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . nodes . borrow_mut () . push (id) ; Process { id , _phantom : PhantomData , } } pub fn cluster < C > (& self) -> Cluster < C > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . clusters . borrow_mut () . push (id) ; Cluster { id , _phantom : PhantomData , } } pub fn runtime_context (& self) -> RuntimeContext < 'a > { RuntimeContext { _phantom : PhantomData , } } pub fn cluster_members < C > (& self , cluster : & Cluster < C > ,) -> impl Quoted < 'a , & 'a Vec < u32 > > + Copy + 'a { ClusterIds { id : cluster . id , _phantom : PhantomData , } } pub fn cluster_self_id < C > (& self , cluster : & Cluster < C >) -> impl Quoted < 'a , u32 > + Copy + 'a { ClusterSelfId { id : cluster . id , _phantom : PhantomData , } } pub fn spin < L : Location > (& self , on : & L) -> Stream < 'a , () , Unbounded , NoTick , L > { Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Spin () , location_kind : on . id () , })) ,) } pub fn spin_batch < L : Location > (& self , on : & L , batch_size : impl Quoted < 'a , usize > + Copy + 'a ,) -> Stream < 'a , () , Bounded , Tick , L > { self . spin (on) . flat_map (q ! (move | _ | 0 .. batch_size)) . map (q ! (| _ | ())) . tick_batch () } pub fn source_stream < T , E : FuturesStream < Item = T > + Unpin , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Unbounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Stream (e . into ()) , location_kind : on . id () , })) ,) } pub fn source_iter < T , E : IntoIterator < Item = T > , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Bounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , })) ,) } pub fn singleton < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Singleton < 'a , T , Bounded , NoTick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Singleton :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,)))) ,) } pub fn singleton_first_tick < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Optional < 'a , T , Bounded , Tick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,) } pub fn source_interval < L : Location > (& self , on : & L , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , () , Unbounded , NoTick , L > { let interval = interval . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : on . id () , })) ,) } pub fn source_interval_delayed < L : Location > (& self , on : & L , delay : impl Quoted < 'a , Duration > + Copy + 'a , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , tokio :: time :: Instant , Unbounded , NoTick , L > { self . source_stream (on , q ! (tokio_stream :: wrappers :: IntervalStream :: new (tokio :: time :: interval_at (tokio :: time :: Instant :: now () + delay , interval))) ,) . tick_batch () . first () . latest () } pub fn cycle < S : CycleCollection < 'a > > (& self , on : & S :: Location) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , on . id ()) ,) } pub fn cycle_with_initial < S : CycleCollectionWithInitial < 'a > > (& self , on : & S :: Location , initial : S ,) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , initial , on . id ()) ,) } } } pub use builder :: FlowBuilder ; pub mod ir { pub use core :: panic ; pub use std :: cell :: RefCell ; pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow_lang :: graph :: FlatGraphBuilder ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: ToTokens ; pub use syn :: parse_quote ; pub use crate :: deploy :: Deploy ; pub use crate :: location :: LocationId ; pub use crate :: ir :: DebugExpr ; # [cfg (stageleft_macro)] impl From < syn :: Expr > for DebugExpr { fn from (expr : syn :: Expr) -> DebugExpr { DebugExpr (expr) } } # [cfg (stageleft_macro)] impl Deref for DebugExpr { type Target = syn :: Expr ; fn deref (& self) -> & Self :: Target { & self . 0 } } # [cfg (stageleft_macro)] impl ToTokens for DebugExpr { fn to_tokens (& self , tokens : & mut TokenStream) { self . 0 . to_tokens (tokens) ; } } # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugExpr { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "{}" , self . 0 . to_token_stream ()) } } pub use crate :: ir :: DebugInstantiate ; # [cfg (stageleft_macro)] impl < 'a > std :: fmt :: Debug for DebugInstantiate < 'a > { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<network instantiate>") } } pub use crate :: ir :: DebugPipelineFn ; # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugPipelineFn { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<function>") } } pub use crate :: ir :: HfPlusSource ; pub use crate :: ir :: HfPlusLeaf ; # [cfg (stageleft_macro)] impl < 'a > HfPlusLeaf < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . compile_network :: < D > (compile_env , s , nodes , clusters) ; } , seen_tees ,) } pub fn connect_network (self , seen_tees : & mut SeenTees < 'a >) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . connect_network (s) ; } , seen_tees ,) } pub fn transform_children (self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) -> HfPlusLeaf < 'a > { match self { HfPlusLeaf :: ForEach { f , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: ForEach { f , input } } HfPlusLeaf :: DestSink { sink , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: DestSink { sink , input } } HfPlusLeaf :: CycleSink { ident , location_kind , mut input , } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: CycleSink { ident , location_kind , input , } } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) { match self { HfPlusLeaf :: ForEach { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> for_each (# f) ; }) ; } HfPlusLeaf :: DestSink { sink , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink) ; }) ; } HfPlusLeaf :: CycleSink { ident , location_kind , input , } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; assert_eq ! (input_location_id , * location_id , "cycle_sink location mismatch") ; graph_builders . entry (* location_id) . or_default () . add_statement (parse_quote ! { # ident = # input_ident ; }) ; } } } } pub use crate :: ir :: HfPlusNode ; pub type SeenTees < 'a > = HashMap < * const RefCell < HfPlusNode < 'a > > , Rc < RefCell < HfPlusNode < 'a > > > > ; # [cfg (stageleft_macro)] impl < 'a > HfPlusNode < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (& mut self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) { self . transform_children (| n , s | n . compile_network :: < D > (compile_env , s , nodes , clusters) , seen_tees ,) ; if let HfPlusNode :: Network { from_location , to_location , instantiate_fn , .. } = self { let (sink_expr , source_expr , connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { let ((sink , source) , connect_fn) = match (from_location , to_location) { (LocationId :: Process (from) , LocationId :: Process (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: o2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Process (from) , LocationId :: Cluster (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: o2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Process (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: m2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Cluster (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: m2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } } ; (sink , source , connect_fn) } DebugInstantiate :: Finalized (_ , _ , _) => panic ! ("network already finalized") , } ; * instantiate_fn = DebugInstantiate :: Finalized (sink_expr , source_expr , connect_fn) ; } } pub fn connect_network (& mut self , seen_tees : & mut SeenTees < 'a >) { self . transform_children (| n , s | n . connect_network (s) , seen_tees) ; if let HfPlusNode :: Network { instantiate_fn , .. } = self { match instantiate_fn { DebugInstantiate :: Building () => panic ! ("network not built") , DebugInstantiate :: Finalized (_ , _ , ref connect_fn) => { connect_fn () ; } } } } pub fn transform_children (& mut self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) { match self { HfPlusNode :: Placeholder => { panic ! () ; } HfPlusNode :: Source { .. } => { } HfPlusNode :: CycleSource { .. } => { } HfPlusNode :: Tee { inner } => { if let Some (transformed) = seen_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { * inner = transformed . clone () ; } else { let transformed_cell = Rc :: new (RefCell :: new (HfPlusNode :: Placeholder)) ; seen_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , transformed_cell . clone () ,) ; let mut orig = inner . replace (HfPlusNode :: Placeholder) ; transform (& mut orig , seen_tees) ; * transformed_cell . borrow_mut () = orig ; * inner = transformed_cell ; } } HfPlusNode :: Persist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Unpersist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Delta (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Union (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossProduct (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossSingleton (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Join (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Difference (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: AntiJoin (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Map { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FlatMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Filter { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FilterMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Sort (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: DeferTick (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Enumerate (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Inspect { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Unique (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Fold { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FoldKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Reduce { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: ReduceKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Network { input , .. } => { transform (input . as_mut () , seen_tees) ; } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) -> (syn :: Ident , usize) { match self { HfPlusNode :: Placeholder => { panic ! () } HfPlusNode :: Persist (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let persist_id = * next_stmt_id ; * next_stmt_id += 1 ; let persist_ident = syn :: Ident :: new (& format ! ("stream_{}" , persist_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # persist_ident = # inner_ident -> persist ::<'static > () ; }) ; (persist_ident , location) } HfPlusNode :: Unpersist (_) => { panic ! ("Unpersist is a marker node and should have been optimized away. This is likely a compiler bug.") } HfPlusNode :: Delta (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let delta_id = * next_stmt_id ; * next_stmt_id += 1 ; let delta_ident = syn :: Ident :: new (& format ! ("stream_{}" , delta_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # delta_ident = # inner_ident -> multiset_delta () ; }) ; (delta_ident , location) } HfPlusNode :: Source { source , location_kind , } => { let source_id = * next_stmt_id ; * next_stmt_id += 1 ; let source_ident = syn :: Ident :: new (& format ! ("stream_{}" , source_id) , Span :: call_site ()) ; let source_stmt = match source { HfPlusSource :: Stream (expr) => { parse_quote ! { # source_ident = source_stream (# expr) ; } } HfPlusSource :: Iter (expr) => { parse_quote ! { # source_ident = source_iter (# expr) ; } } HfPlusSource :: Interval (expr) => { parse_quote ! { # source_ident = source_interval (# expr) ; } } HfPlusSource :: Spin () => { parse_quote ! { # source_ident = spin () ; } } } ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; graph_builders . entry (* location_id) . or_default () . add_statement (source_stmt) ; (source_ident , * location_id) } HfPlusNode :: CycleSource { ident , location_kind , } => { let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; (ident . clone () , * location_id) } HfPlusNode :: Tee { inner } => { if let Some (ret) = built_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { ret . clone () } else { let (inner_ident , inner_location_id) = inner . borrow () . emit (graph_builders , built_tees , next_stmt_id) ; let tee_id = * next_stmt_id ; * next_stmt_id += 1 ; let tee_ident = syn :: Ident :: new (& format ! ("stream_{}" , tee_id) , Span :: call_site ()) ; let builder = graph_builders . entry (inner_location_id) . or_default () ; builder . add_statement (parse_quote ! { # tee_ident = # inner_ident -> tee () ; }) ; built_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , (tee_ident . clone () , inner_location_id) ,) ; (tee_ident , inner_location_id) } } HfPlusNode :: Union (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "union inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let union_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # union_ident = union () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [0] # union_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # union_ident ; }) ; (union_ident , left_location_id) } HfPlusNode :: CrossSingleton (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "cross_singleton inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let cross_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # cross_ident = cross_singleton () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [input] # cross_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [single] # cross_ident ; }) ; (cross_ident , left_location_id) } HfPlusNode :: CrossProduct (..) | HfPlusNode :: Join (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: CrossProduct (..)) { parse_quote ! (cross_join_multiset) } else { parse_quote ! (join_multiset) } ; let (HfPlusNode :: CrossProduct (left , right) | HfPlusNode :: Join (left , right)) = self else { unreachable ! () } ; let (left_inner , left_was_persist) = if let HfPlusNode :: Persist (left) = left . as_ref () { (left , true) } else { (left , false) } ; let (right_inner , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left_inner . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right_inner . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "join / cross product inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; match (left_was_persist , right_was_persist) { (true , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'static > () ; }) ; } (true , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'tick > () ; }) ; } (false , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } (false , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } } ; builder . add_statement (parse_quote ! { # left_ident -> [0] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Difference (..) | HfPlusNode :: AntiJoin (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Difference (..)) { parse_quote ! (difference_multiset) } else { parse_quote ! (anti_join_multiset) } ; let (HfPlusNode :: Difference (left , right) | HfPlusNode :: AntiJoin (left , right)) = self else { unreachable ! () } ; let (right , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "difference / anti join inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; if right_was_persist { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } else { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } builder . add_statement (parse_quote ! { # left_ident -> [pos] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [neg] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Map { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let map_id = * next_stmt_id ; * next_stmt_id += 1 ; let map_ident = syn :: Ident :: new (& format ! ("stream_{}" , map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # map_ident = # input_ident -> map (# f) ; }) ; (map_ident , input_location_id) } HfPlusNode :: FlatMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let flat_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let flat_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , flat_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # flat_map_ident = # input_ident -> flat_map (# f) ; }) ; (flat_map_ident , input_location_id) } HfPlusNode :: Filter { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_ident = # input_ident -> filter (# f) ; }) ; (filter_ident , input_location_id) } HfPlusNode :: FilterMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_map_ident = # input_ident -> filter_map (# f) ; }) ; (filter_map_ident , input_location_id) } HfPlusNode :: Sort (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sort_id = * next_stmt_id ; * next_stmt_id += 1 ; let sort_ident = syn :: Ident :: new (& format ! ("stream_{}" , sort_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # sort_ident = # input_ident -> sort () ; }) ; (sort_ident , input_location_id) } HfPlusNode :: DeferTick (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let defer_tick_id = * next_stmt_id ; * next_stmt_id += 1 ; let defer_tick_ident = syn :: Ident :: new (& format ! ("stream_{}" , defer_tick_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # defer_tick_ident = # input_ident -> defer_tick_lazy () ; }) ; (defer_tick_ident , input_location_id) } HfPlusNode :: Enumerate (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let enumerate_id = * next_stmt_id ; * next_stmt_id += 1 ; let enumerate_ident = syn :: Ident :: new (& format ! ("stream_{}" , enumerate_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # enumerate_ident = # input_ident -> enumerate () ; }) ; (enumerate_ident , input_location_id) } HfPlusNode :: Inspect { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let inspect_id = * next_stmt_id ; * next_stmt_id += 1 ; let inspect_ident = syn :: Ident :: new (& format ! ("stream_{}" , inspect_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # inspect_ident = # input_ident -> inspect (# f) ; }) ; (inspect_ident , input_location_id) } HfPlusNode :: Unique (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let unique_id = * next_stmt_id ; * next_stmt_id += 1 ; let unique_ident = syn :: Ident :: new (& format ! ("stream_{}" , unique_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # unique_ident = # input_ident -> unique ::<'tick > () ; }) ; (unique_ident , input_location_id) } HfPlusNode :: Fold { .. } | HfPlusNode :: FoldKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Fold { .. }) { parse_quote ! (fold) } else { parse_quote ! (fold_keyed) } ; let (HfPlusNode :: Fold { init , acc , input } | HfPlusNode :: FoldKeyed { init , acc , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let fold_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'static > (# init , # acc) ; }) ; } else { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'tick > (# init , # acc) ; }) ; } (fold_ident , input_location_id) } HfPlusNode :: Reduce { .. } | HfPlusNode :: ReduceKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Reduce { .. }) { parse_quote ! (reduce) } else { parse_quote ! (reduce_keyed) } ; let (HfPlusNode :: Reduce { f , input } | HfPlusNode :: ReduceKeyed { f , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let reduce_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'static > (# f) ; }) ; } else { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'tick > (# f) ; }) ; } (reduce_ident , input_location_id) } HfPlusNode :: Network { from_location : _ , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input , } => { let (sink_expr , source_expr , _connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { panic ! ("Expected the network to be finalized") } DebugInstantiate :: Finalized (sink , source , connect_fn) => { (sink , source , connect_fn) } } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sender_builder = graph_builders . entry (input_location_id) . or_default () ; if let Some (serialize_pipeline) = serialize_pipeline { sender_builder . add_statement (parse_quote ! { # input_ident -> # serialize_pipeline -> dest_sink (# sink_expr) ; }) ; } else { sender_builder . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink_expr) ; }) ; } let to_id = match to_location { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let receiver_builder = graph_builders . entry (* to_id) . or_default () ; let receiver_stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let receiver_stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , receiver_stream_id) , Span :: call_site ()) ; if let Some (deserialize_pipeline) = deserialize_pipeline { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) -> # deserialize_pipeline ; }) ; } else { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) ; }) ; } (receiver_stream_ident , * to_id) } } } } } pub mod persist_pullup { pub use std :: cell :: RefCell ; pub use std :: collections :: HashSet ; pub use std :: ops :: Deref ; pub use crate :: ir :: * ; pub fn persist_pullup_node < 'a > (node : & mut HfPlusNode < 'a > , seen_tees : & mut SeenTees < 'a > , persist_pulled_tees : & mut HashSet < * const RefCell < HfPlusNode < 'a > > > ,) { node . transform_children (| n , s | persist_pullup_node (n , s , persist_pulled_tees) , seen_tees ,) ; match node { HfPlusNode :: Unpersist (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Unpersist (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Delta (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Delta (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Tee { inner } => { if persist_pulled_tees . contains (& (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >)) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } else { let inner_borrow = inner . borrow () ; if let HfPlusNode :: Persist (_) = inner_borrow . deref () { drop (inner_borrow) ; persist_pulled_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >) ; if let HfPlusNode :: Persist (box behind_persist) = inner . replace (HfPlusNode :: Placeholder) { * inner . borrow_mut () = behind_persist ; } else { unreachable ! () } * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } } } HfPlusNode :: Map { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Map { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Map { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: FlatMap { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: FlatMap { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: FlatMap { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Filter { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Filter { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Filter { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Network { input : box HfPlusNode :: Persist (_) , .. } => { if let HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Union (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Union (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Union (left , right))) ; } else { unreachable ! () } } HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: CrossProduct (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,) ,)))) ; } else { unreachable ! () } } HfPlusNode :: Join (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Join (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: Join (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,))))) ; } else { unreachable ! () } } _ => { } } } pub fn persist_pullup (ir : Vec < HfPlusLeaf >) -> Vec < HfPlusLeaf > { let mut seen_tees = Default :: default () ; let mut persist_pulled_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| n , s | persist_pullup_node (n , s , & mut persist_pulled_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn persist_pullup_through_map () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } # [test] fn persist_pullup_behind_tee () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; let before_tee = flow . source_iter (& process , q ! (0 .. 10)) . tick_batch () . persist () ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } } } pub mod profiler { pub use std :: cell :: RefCell ; pub use hydroflow :: futures :: channel :: mpsc :: UnboundedSender ; pub use stageleft :: * ; pub use crate as hydroflow_plus ; pub use crate :: ir :: * ; pub use crate :: RuntimeContext ; pub fn increment_counter (count : & mut u64) { * count += 1 ; } pub fn quoted_any_fn < 'a , F : Fn (& usize) + 'a , Q : IntoQuotedMut < 'a , F > > (q : Q) -> Q { q } # [doc = " Add a profiling node before each node to count the cardinality of its input"] pub fn add_profiling_node < 'a > (node : & mut HfPlusNode < 'a > , _context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > , id : & mut u32 , seen_tees : & mut SeenTees < 'a > ,) { let my_id = * id ; * id += 1 ; node . transform_children (| node , seen_tees | { add_profiling_node (node , _context , counters , counter_queue , id , seen_tees) } , seen_tees ,) ; let orig_node = std :: mem :: replace (node , HfPlusNode :: Placeholder) ; * node = HfPlusNode :: Inspect { f : quoted_any_fn (q ! ({ counter_queue . borrow () . unbounded_send ((my_id as usize , counters . borrow () [my_id as usize])) . unwrap () ; counters . borrow_mut () [my_id as usize] = 0 ; move | _ | { hydroflow_plus :: profiler :: increment_counter (& mut counters . borrow_mut () [my_id as usize] ,) ; } })) . splice () . into () , input : Box :: new (orig_node) , } } # [doc = " Count the cardinality of each input and periodically output to a file"] pub fn profiling < 'a > (ir : Vec < HfPlusLeaf < 'a > > , context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > ,) -> Vec < HfPlusLeaf < 'a > > { let mut id = 0 ; let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | { add_profiling_node (node , context , counters , counter_queue , & mut id , seen_tees) } , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn profiler_wrapping_all_operators () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let runtime_context = flow . runtime_context () ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (& built . ir ()) ; let counters = RuntimeData :: new ("Fake") ; let counter_queue = RuntimeData :: new ("Fake") ; let pushed_down = built . with_default_optimize () . optimize_with (| ir | super :: profiling (ir , runtime_context , counters , counter_queue)) ; insta :: assert_debug_snapshot ! (& pushed_down . ir ()) ; let _ = pushed_down . compile_no_network :: < MultiGraph > () ; } } } pub mod properties { pub use std :: collections :: HashSet ; pub use stageleft :: * ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , SeenTees } ; pub use crate :: properties :: PropertyDatabase ; # [doc = " Allows us to convert the hydroflow datatype for folds to a binary operation for the algebra"] # [doc = " property tests."] # [allow (dead_code)] pub fn convert_hf_to_binary < I , A : Default , F : Fn (& mut A , I) > (f : F) -> impl Fn (I , I) -> A { move | a , b | { let mut acc = Default :: default () ; f (& mut acc , a) ; f (& mut acc , b) ; acc } } # [cfg (stageleft_macro)] impl PropertyDatabase { # [doc = " Tags the expression as commutative."] pub fn add_commutative_tag < 'a , I , A , F : Fn (& mut A , I) , Q : Quoted < 'a , F > + Clone > (& mut self , expr : Q ,) -> Q { let expr_clone = expr . clone () ; self . commutative . insert (expr_clone . splice ()) ; expr } pub fn is_tagged_commutative (& self , expr : & syn :: Expr) -> bool { self . commutative . contains (expr) } } pub fn properties_optimize_node < 'a > (node : & mut HfPlusNode < 'a > , db : & PropertyDatabase , seen_tees : & mut SeenTees < 'a > ,) { node . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , seen_tees ,) ; match node { HfPlusNode :: ReduceKeyed { f , .. } if db . is_tagged_commutative (& f . 0) => { dbg ! ("IDENTIFIED COMMUTATIVE OPTIMIZATION for {:?}" , & f) ; } _ => { } } } pub fn properties_optimize < 'a > (ir : Vec < HfPlusLeaf < 'a > > , db : & PropertyDatabase ,) -> Vec < HfPlusLeaf < 'a > > { let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use super :: * ; use crate :: deploy :: SingleProcessGraph ; use crate :: FlowBuilder ; # [test] fn test_property_database () { let mut db = PropertyDatabase :: default () ; assert ! (! db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; let _ = db . add_commutative_tag (q ! (| a : & mut i32 , b : i32 | * a += b)) ; assert ! (db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; } # [test] fn test_property_optimized () { let flow = FlowBuilder :: new () ; let mut database = PropertyDatabase :: default () ; let process = flow . process :: < () > () ; let counter_func = q ! (| count : & mut i32 , _ | * count += 1) ; let _ = database . add_commutative_tag (counter_func) ; flow . source_iter (& process , q ! (vec ! [])) . map (q ! (| string : String | (string , ()))) . tick_batch () . fold_keyed (q ! (|| 0) , counter_func) . all_ticks () . for_each (q ! (| (string , count) | println ! ("{}: {}" , string , count))) ; let built = flow . finalize () . optimize_with (| ir | properties_optimize (ir , & database)) . with_default_optimize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let _ = built . compile_no_network :: < SingleProcessGraph > () ; } } } pub use crate :: RuntimeContext ; # [cfg (stageleft_macro)] impl Copy for RuntimeContext < '_ > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Context > for RuntimeContext < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (quote ! (& context))) } } pub use crate :: HfCompiled ; # [cfg (stageleft_macro)] impl < 'a , ID > HfCompiled < 'a , ID > { pub fn hydroflow_ir (& self) -> & BTreeMap < usize , HydroflowGraph > { & self . hydroflow_ir } } # [cfg (stageleft_macro)] impl < 'a > HfCompiled < 'a , usize > { pub fn with_dynamic_id (self , id : impl Quoted < 'a , usize >) -> HfBuiltWithId < 'a > { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; let mut conditioned_tokens = None ; for (subgraph_id , flat_graph) in self . hydroflow_ir { let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; let my_extra_stmts = self . extra_stmts . get (& subgraph_id) . cloned () . unwrap_or_default () ; if let Some (conditioned_tokens) = conditioned_tokens . as_mut () { * conditioned_tokens = syn :: parse_quote ! { # conditioned_tokens else if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } } ; } else { conditioned_tokens = Some (syn :: parse_quote ! { if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } }) ; } } let conditioned_tokens : TokenStream = conditioned_tokens . unwrap () ; let id = id . splice () ; HfBuiltWithId { tokens : syn :: parse_quote ! ({ let __given_id = # id ; # conditioned_tokens else { panic ! ("Invalid node id: {}" , __given_id) ; } }) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfCompiled < 'a , () > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfCompiled < 'a , () > { fn to_tokens (mut self) -> (Option < TokenStream > , Option < TokenStream >) { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; if self . hydroflow_ir . len () != 1 { panic ! ("Expected exactly one subgraph in the Hydroflow IR") ; } let flat_graph = self . hydroflow_ir . remove (& 0) . unwrap () ; let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; (None , Some (tokens)) } } pub use crate :: HfBuiltWithId ; # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfBuiltWithId < 'a > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfBuiltWithId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (self . tokens)) } }
[INFO] [stdout] 1 + pub use std :: collections :: BTreeMap ; pub use std :: marker :: PhantomData ; pub use hydroflow :: scheduled :: context :: Context ; pub use hydroflow :: scheduled :: graph :: Hydroflow ; pub use hydroflow :: * ; pub use lang :: graph :: { partition_graph , HydroflowGraph } ; pub use proc_macro2 :: TokenStream ; pub use quote :: quote ; pub use stageleft :: runtime_support :: FreeVariable ; pub use stageleft :: Quoted ; pub mod runtime_support { pub use bincode ; } pub mod stream { pub use std :: cell :: RefCell ; pub use std :: hash :: Hash ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow :: bytes :: Bytes ; pub use hydroflow :: futures :: Sink ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: quote ; pub use serde :: de :: DeserializeOwned ; pub use serde :: Serialize ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use syn :: parse_quote ; pub use crate :: builder :: { ClusterIds , FlowLeaves } ; pub use crate :: cycle :: { CycleCollection , CycleComplete } ; pub use crate :: ir :: { DebugInstantiate , HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { CanSend , Location , LocationId } ; pub use crate :: { Cluster , Optional , Singleton } ; pub use crate :: stream :: Unbounded ; pub use crate :: stream :: Bounded ; pub use crate :: stream :: NoTick ; pub use crate :: stream :: Tick ; pub use crate :: stream :: Stream ; # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Stream { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Stream < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Stream { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , C , N > > ,) -> Stream < 'a , (T , O) , W , C , N > where O : Clone , { let other : Optional < 'a , O , Bounded , C , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn cross_product < O > (self , other : Stream < 'a , O , W , C , N >) -> Stream < 'a , (T , O) , W , C , N > where T : Clone , O : Clone , { if self . location_kind != other . location_kind { panic ! ("cross_product must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossProduct (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn union (self , other : Stream < 'a , T , W , C , N >) -> Stream < 'a , T , W , C , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn dest_sink < S : Unpin + Sink < T > + 'a > (self , sink : impl Quoted < 'a , S >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: DestSink { sink : sink . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn first (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } # [doc = " Allow this stream through if the other stream has elements, otherwise the output is empty."] pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } # [doc = " Allow this stream through if the other stream is empty, otherwise the output is empty."] pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn enumerate (self) -> Stream < 'a , (usize , T) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Enumerate (Box :: new (self . ir_node . into_inner ())) ,) } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn sort (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Ord , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Sort (Box :: new (self . ir_node . into_inner ())) ,) } pub fn count (self) -> Singleton < 'a , usize , Bounded , Tick , N > { self . fold (q ! (|| 0usize) , q ! (| count , _ | * count += 1)) } pub fn delta (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } pub fn unique (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Eq + Hash , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unique (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn tick_batch (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_prefix (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { self . tick_batch () . persist () } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn for_each < F : Fn (T) + 'a > (self , f : impl IntoQuotedMut < 'a , F >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: ForEach { input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , f : f . splice () . into () , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Unbounded , NoTick , N > { pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . tick_batch () . continue_if (samples . first ()) . all_ticks () } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Unbounded , NoTick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , C , N : Location > Stream < 'a , T , Bounded , C , N > { pub fn filter_not_in (self , other : Stream < 'a , T , Bounded , C , N >) -> Stream < 'a , T , Bounded , C , N > where T : Eq + Hash , { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Difference (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Stream < 'a , & T , W , C , N > { pub fn cloned (self) -> Stream < 'a , T , W , C , N > { self . map (q ! (| d | d . clone ())) } } # [cfg (stageleft_macro)] impl < 'a , K , V1 , W , C , N : Location > Stream < 'a , (K , V1) , W , C , N > { pub fn join < W2 , V2 > (self , n : Stream < 'a , (K , V2) , W2 , C , N > ,) -> Stream < 'a , (K , (V1 , V2)) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Join (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } pub fn anti_join < W2 > (self , n : Stream < 'a , K , W2 , C , N >) -> Stream < 'a , (K , V1) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("anti_join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: AntiJoin (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , K : Eq + Hash , V , N : Location > Stream < 'a , (K , V) , Bounded , Tick , N > { pub fn fold_keyed < A , I : Fn () -> A + 'a , F : Fn (& mut A , V) + 'a > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , A) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FoldKeyed { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce_keyed < F : Fn (& mut V , V) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , V) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: ReduceKeyed { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } pub fn get_this_crate () -> TokenStream { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , Span :: call_site ()) ; quote ! { # ident } } } } pub fn serialize_bincode < T : Serialize > (is_demux : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if is_demux { parse_quote ! { map (| (id , data) | { (id , # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into ()) }) } } else { parse_quote ! { map (| data | { # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into () }) } } } pub fn deserialize_bincode < T : DeserializeOwned > (tagged : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if tagged { parse_quote ! { map (| res | { let (id , b) = res . unwrap () ; (id , # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& b) . unwrap ()) }) } } else { parse_quote ! { map (| res | { # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& res . unwrap ()) . unwrap () }) } } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn send_bincode < N2 : Location , CoreType > (self , other : & N2 ,) -> Stream < 'a , N :: Out < CoreType > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T > , CoreType : Serialize + DeserializeOwned , { let serialize_pipeline = Some (serialize_bincode :: < CoreType > (N :: is_demux ())) ; let deserialize_pipeline = Some (deserialize_bincode :: < CoreType > (N :: is_tagged ())) ; Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bytes < N2 : Location > (self , other : & N2 ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T > , { Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline : None , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline : if N :: is_tagged () { Some (parse_quote ! (map (| (id , b) | (id , b . unwrap () . freeze ())))) } else { Some (parse_quote ! (map (| b | b . unwrap () . freeze ()))) } , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bincode_interleaved < N2 : Location , Tag , CoreType > (self , other : & N2 ,) -> Stream < 'a , CoreType , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T , Out < CoreType > = (Tag , CoreType) > , CoreType : Serialize + DeserializeOwned , { self . send_bincode :: < N2 , CoreType > (other) . map (q ! (| (_ , b) | b)) } pub fn send_bytes_interleaved < N2 : Location , Tag > (self , other : & N2 ,) -> Stream < 'a , Bytes , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T , Out < Bytes > = (Tag , Bytes) > , { self . send_bytes :: < N2 > (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bincode < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < T > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) > , T : Clone + Serialize + DeserializeOwned , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bincode (other) } pub fn broadcast_bincode_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , T , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) , Out < T > = (Tag , T) > + 'a , T : Clone + Serialize + DeserializeOwned , { self . broadcast_bincode (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bytes < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) > + 'a , T : Clone , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bytes (other) } pub fn broadcast_bytes_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , Bytes , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) , Out < Bytes > = (Tag , Bytes) > + 'a , T : Clone , { self . broadcast_bytes (other) . map (q ! (| (_ , b) | b)) } } } pub use stream :: { Bounded , NoTick , Stream , Tick , Unbounded } ; pub mod singleton { pub use std :: cell :: RefCell ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use crate :: builder :: FlowLeaves ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial , CycleComplete } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: Stream ; pub use crate :: singleton :: CrossResult ; # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Singleton < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Singleton :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } pub use crate :: singleton :: Singleton ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Singleton { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleComplete < 'a > for Singleton < 'a , T , Bounded , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleCollectionWithInitial < 'a > for Singleton < 'a , T , Bounded , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , initial : Self , l : LocationId ,) -> Self { Singleton :: new (l , ir_leaves , HfPlusNode :: Union (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , }) , initial . ir_node . into_inner () . into () ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Singleton < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Singleton { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , U , W , C , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (Self :: other_ir_node (other)) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Singleton < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CrossSingleton (Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , Box :: new (HfPlusNode :: Unpersist (Box :: new (Self :: other_ir_node (other)))) ,))) ,) } } pub use crate :: singleton :: Optional ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Optional { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } pub fn some (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: new (singleton . location_kind , singleton . ir_leaves , singleton . ir_node . into_inner () ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > From < Singleton < 'a , T , W , C , N > > for Optional < 'a , T , W , C , N > { fn from (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: some (singleton) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Optional < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Optional { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn into_stream (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , Tick , N > > ,) -> Optional < 'a , (T , O) , Bounded , Tick , N > where O : Clone , { let other : Optional < 'a , O , Bounded , Tick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn union (self , other : Optional < 'a , T , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Optional < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_samples (self) -> Stream < 'a , T , Unbounded , NoTick , N > { self . latest_tick () . all_ticks () } pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . latest_tick () . continue_if (samples . first ()) . latest () . tick_samples () } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Unbounded , NoTick , N > > ,) -> Optional < 'a , (T , O) , Unbounded , NoTick , N > where O : Clone , { let other : Optional < 'a , O , Unbounded , NoTick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } self . latest_tick () . cross_singleton (other . latest_tick ()) . latest () } } } pub use singleton :: { Optional , Singleton } ; pub mod location { pub use std :: marker :: PhantomData ; pub use crate :: location :: LocationId ; pub use crate :: location :: Location ; pub use crate :: location :: Process ; # [cfg (stageleft_macro)] impl < P > Clone for Process < P > { fn clone (& self) -> Self { Process { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < P > Location for Process < P > { fn id (& self) -> LocationId { LocationId :: Process (self . id) } } pub use crate :: location :: Cluster ; # [cfg (stageleft_macro)] impl < C > Clone for Cluster < C > { fn clone (& self) -> Self { Cluster { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < C > Location for Cluster < C > { fn id (& self) -> LocationId { LocationId :: Cluster (self . id) } } pub use crate :: location :: CanSend ; # [cfg (stageleft_macro)] impl < P1 , P2 > CanSend < Process < P2 > > for Process < P1 > { type In < T > = T ; type Out < T > = T ; fn is_demux () -> bool { false } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < P1 , C2 > CanSend < Cluster < C2 > > for Process < P1 > { type In < T > = (u32 , T) ; type Out < T > = T ; fn is_demux () -> bool { true } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < C1 , P2 > CanSend < Process < P2 > > for Cluster < C1 > { type In < T > = T ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { false } fn is_tagged () -> bool { true } } # [cfg (stageleft_macro)] impl < C1 , C2 > CanSend < Cluster < C2 > > for Cluster < C1 > { type In < T > = (u32 , T) ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { true } fn is_tagged () -> bool { true } } } pub use location :: { Cluster , Process } ; pub mod deploy { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use stageleft :: Quoted ; pub mod graphs { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use super :: { LocalDeploy , Node , ProcessSpec } ; pub use crate :: deploy :: graphs :: SingleProcessGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for SingleProcessGraph { type Process = SingleNode ; type Cluster = SingleNode ; type Meta = () ; type GraphId = () ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { SingleNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { SingleNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , SingleProcessGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> SingleNode { SingleNode { } } } pub use crate :: deploy :: graphs :: SingleNode ; # [cfg (stageleft_macro)] impl Node for SingleNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } pub use crate :: deploy :: graphs :: MultiGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for MultiGraph { type Process = MultiNode ; type Cluster = MultiNode ; type Meta = () ; type GraphId = usize ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { MultiNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { MultiNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , MultiGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> MultiNode { MultiNode { } } } pub use crate :: deploy :: graphs :: MultiNode ; # [cfg (stageleft_macro)] impl Node for MultiNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } } pub use graphs :: * ; pub use crate :: deploy :: LocalDeploy ; pub use crate :: deploy :: Deploy ; # [cfg (stageleft_macro)] impl < 'a , T : Deploy < 'a , Process = N , Cluster = C , Meta = M , GraphId = R > , N : Node < Meta = M > , C : Node < Meta = M > , M : Default , R , > LocalDeploy < 'a > for T { type Process = N ; type Cluster = C ; type Meta = M ; type GraphId = R ; fn has_trivial_node () -> bool { < T as Deploy < 'a > > :: has_trivial_node () } fn trivial_process (id : usize) -> Self :: Process { < T as Deploy < 'a > > :: trivial_process (id) } fn trivial_cluster (id : usize) -> Self :: Cluster { < T as Deploy < 'a > > :: trivail_cluster (id) } } pub use crate :: deploy :: ProcessSpec ; pub use crate :: deploy :: ClusterSpec ; pub use crate :: deploy :: Node ; } pub use deploy :: { ClusterSpec , Deploy , ProcessSpec } ; pub mod cycle { pub use std :: marker :: PhantomData ; pub use crate :: builder :: FlowLeaves ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: cycle :: CycleComplete ; pub use crate :: cycle :: CycleCollection ; pub use crate :: cycle :: CycleCollectionWithInitial ; pub use crate :: cycle :: HfCycle ; # [cfg (stageleft_macro)] impl < 'a , S : CycleComplete < 'a > > HfCycle < 'a , S > { pub fn complete (self , stream : S) { let ident = self . ident ; S :: complete (stream , ident) } } } pub use cycle :: HfCycle ; pub mod builder { pub use std :: cell :: RefCell ; pub use std :: collections :: HashMap ; pub use std :: marker :: PhantomData ; pub use std :: rc :: Rc ; pub use std :: time :: Duration ; pub use hydroflow :: futures :: stream :: Stream as FuturesStream ; pub use hydroflow :: { tokio , tokio_stream } ; pub use internal :: TokenStream ; pub use proc_macro2 :: Span ; pub use quote :: quote ; pub use runtime_support :: FreeVariable ; pub use stageleft :: * ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Cluster , Location , LocationId , Process } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: { HfCycle , Optional , RuntimeContext , Singleton , Stream } ; pub mod built { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use hydroflow_lang :: graph :: { eliminate_extra_unions_tees , HydroflowGraph } ; pub use super :: deploy :: { DeployFlow , DeployResult } ; pub use crate :: deploy :: { ClusterSpec , Deploy , LocalDeploy , ProcessSpec } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Cluster , Process } ; pub use crate :: HfCompiled ; pub use crate :: builder :: built :: BuiltFlow ; # [cfg (stageleft_macro)] impl < 'a > Drop for BuiltFlow < 'a > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped BuiltFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn ir (& self) -> & Vec < HfPlusLeaf < 'a > > { & self . ir } pub fn optimize_with (mut self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> BuiltFlow < 'a > { self . used = true ; BuiltFlow { ir : f (std :: mem :: take (& mut self . ir)) , processes : std :: mem :: take (& mut self . processes) , clusters : std :: mem :: take (& mut self . clusters) , used : false , _phantom : PhantomData , } } } pub fn build_inner (ir : & mut Vec < HfPlusLeaf >) -> BTreeMap < usize , HydroflowGraph > { let mut builders = BTreeMap :: new () ; let mut built_tees = HashMap :: new () ; let mut next_stmt_id = 0 ; for leaf in ir { leaf . emit (& mut builders , & mut built_tees , & mut next_stmt_id) ; } builders . into_iter () . map (| (k , v) | { let (mut flat_graph , _ , _) = v . build () ; eliminate_extra_unions_tees (& mut flat_graph) ; (k , flat_graph) }) . collect () } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn compile_no_network < D : LocalDeploy < 'a > > (mut self) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; HfCompiled { hydroflow_ir : build_inner (& mut self . ir) , extra_stmts : BTreeMap :: new () , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> BuiltFlow < 'a > { self . optimize_with (crate :: persist_pullup :: persist_pullup) } fn into_deploy < D : LocalDeploy < 'a > > (mut self) -> DeployFlow < 'a , D > { self . used = true ; let processes = if D :: has_trivial_node () { self . processes . iter () . map (| id | (* id , D :: trivial_process (* id))) . collect () } else { HashMap :: new () } ; let clusters = if D :: has_trivial_node () { self . clusters . iter () . map (| id | (* id , D :: trivial_cluster (* id))) . collect () } else { HashMap :: new () } ; DeployFlow { ir : std :: mem :: take (& mut self . ir) , nodes : processes , clusters , used : false , _phantom : PhantomData , } } pub fn with_process < P , D : LocalDeploy < 'a > > (self , process : & Process < P > , spec : impl ProcessSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_process (process , spec) } pub fn with_cluster < C , D : LocalDeploy < 'a > > (self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_cluster (cluster , spec) } pub fn compile < D : Deploy < 'a > + 'a > (self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . into_deploy :: < D > () . compile (env) } pub fn deploy < D : Deploy < 'a , CompileEnv = () > + 'a > (self , env : & mut D :: InstantiateEnv ,) -> DeployResult < 'a , D > { self . into_deploy :: < D > () . deploy (env) } } } pub mod deploy { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use proc_macro2 :: Span ; pub use stageleft :: Quoted ; pub use super :: built :: build_inner ; pub use crate :: deploy :: { LocalDeploy , Node } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: { Cluster , ClusterSpec , Deploy , HfCompiled , Process , ProcessSpec } ; pub use crate :: builder :: deploy :: DeployFlow ; # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > Drop for DeployFlow < 'a , D > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped DeployFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > DeployFlow < 'a , D > { pub fn with_process < P > (mut self , process : & Process < P > , spec : impl ProcessSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < P > () . to_string () ; self . nodes . insert (process . id , spec . build (process . id , & tag_name)) ; self } pub fn with_cluster < C > (mut self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < C > () . to_string () ; self . clusters . insert (cluster . id , spec . build (cluster . id , & tag_name)) ; self } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployFlow < 'a , D > { pub fn compile (mut self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; let mut seen_tees : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | leaf . compile_network :: < D > (env , & mut seen_tees , & self . nodes , & self . clusters)) . collect () ; let extra_stmts = self . extra_stmts (env) ; HfCompiled { hydroflow_ir : build_inner (& mut ir_leaves_networked) , extra_stmts , _phantom : PhantomData , } } fn extra_stmts (& self , env : & < D as Deploy < 'a > > :: CompileEnv) -> BTreeMap < usize , Vec < syn :: Stmt > > { let all_locations_count = self . nodes . len () + self . clusters . len () ; let mut extra_stmts : BTreeMap < usize , Vec < syn :: Stmt > > = BTreeMap :: new () ; for & c_id in self . clusters . keys () { let self_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , c_id) , Span :: call_site () ,) ; let self_id_expr = D :: cluster_self_id (env) . splice () ; extra_stmts . entry (c_id) . or_default () . push (syn :: parse_quote ! { let # self_id_ident = # self_id_expr ; }) ; for other_location in 0 .. all_locations_count { let other_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , c_id) , Span :: call_site () ,) ; let other_id_expr = D :: cluster_ids (env , c_id) . splice () ; extra_stmts . entry (other_location) . or_default () . push (syn :: parse_quote ! { let # other_id_ident = # other_id_expr ; }) ; } } extra_stmts } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a , CompileEnv = () > > DeployFlow < 'a , D > { # [must_use] pub fn deploy (mut self , env : & mut D :: InstantiateEnv) -> DeployResult < 'a , D > { self . used = true ; let mut seen_tees_instantiate : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | { leaf . compile_network :: < D > (& () , & mut seen_tees_instantiate , & self . nodes , & self . clusters ,) }) . collect () ; let mut compiled = build_inner (& mut ir_leaves_networked) ; let mut extra_stmts = self . extra_stmts (& ()) ; let mut meta = D :: Meta :: default () ; let (mut processes , mut clusters) = (std :: mem :: take (& mut self . nodes) . into_iter () . map (| (node_id , node) | { node . instantiate (env , & mut meta , compiled . remove (& node_id) . unwrap () , extra_stmts . remove (& node_id) . unwrap_or_default () ,) ; (node_id , node) }) . collect :: < HashMap < _ , _ > > () , std :: mem :: take (& mut self . clusters) . into_iter () . map (| (cluster_id , cluster) | { cluster . instantiate (env , & mut meta , compiled . remove (& cluster_id) . unwrap () , extra_stmts . remove (& cluster_id) . unwrap_or_default () ,) ; (cluster_id , cluster) }) . collect :: < HashMap < _ , _ > > () ,) ; for node in processes . values_mut () { node . update_meta (& meta) ; } for cluster in clusters . values_mut () { cluster . update_meta (& meta) ; } let mut seen_tees_connect = HashMap :: new () ; for leaf in ir_leaves_networked { leaf . connect_network (& mut seen_tees_connect) ; } DeployResult { processes , clusters , } } } pub use crate :: builder :: deploy :: DeployResult ; # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployResult < 'a , D > { pub fn get_process < P > (& self , p : & Process < P >) -> & D :: Process { let id = match p . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . processes . get (& id) . unwrap () } pub fn get_cluster < C > (& self , c : & Cluster < C >) -> & D :: Cluster { let id = match c . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . clusters . get (& id) . unwrap () } } } # [doc = " Tracks the leaves of the dataflow IR. This is referenced by"] # [doc = " `Stream` and `HfCycle` to build the IR. The inner option will"] # [doc = " be set to `None` when this builder is finalized."] pub type FlowLeaves < 'a > = Rc < RefCell < Option < Vec < HfPlusLeaf < 'a > > > > > ; pub use crate :: builder :: ClusterIds ; # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Vec < u32 > > for ClusterIds < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , & 'a Vec < u32 > > for ClusterIds < 'a > { } # [derive (Copy , Clone)] pub struct ClusterSelfId < 'a > { pub id : usize , pub _phantom : PhantomData < & 'a mut & 'a u32 > , } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < u32 > for ClusterSelfId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , u32 > for ClusterSelfId < 'a > { } pub use crate :: builder :: FlowBuilder ; # [cfg (stageleft_macro)] impl < 'a > Drop for FlowBuilder < 'a > { fn drop (& mut self) { if ! self . finalized { panic ! ("Dropped FlowBuilder without finalizing, you may have forgotten to call `with_default_optimize`, `optimize_with`, or `finalize`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > QuotedContext for FlowBuilder < 'a > { fn create () -> Self { FlowBuilder :: new () } } # [cfg (stageleft_macro)] impl < 'a > FlowBuilder < 'a > { # [allow (clippy :: new_without_default)] pub fn new () -> FlowBuilder < 'a > { FlowBuilder { ir_leaves : Rc :: new (RefCell :: new (Some (Vec :: new ()))) , nodes : RefCell :: new (vec ! []) , clusters : RefCell :: new (vec ! []) , cycle_ids : RefCell :: new (HashMap :: new ()) , next_node_id : RefCell :: new (0) , finalized : false , _phantom : PhantomData , } } pub fn finalize (mut self) -> built :: BuiltFlow < 'a > { self . finalized = true ; built :: BuiltFlow { ir : self . ir_leaves . borrow_mut () . take () . unwrap () , processes : self . nodes . replace (vec ! []) , clusters : self . clusters . replace (vec ! []) , used : false , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> built :: BuiltFlow < 'a > { self . finalize () . with_default_optimize () } pub fn optimize_with (self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> built :: BuiltFlow < 'a > { self . finalize () . optimize_with (f) } pub fn ir_leaves (& self) -> & FlowLeaves < 'a > { & self . ir_leaves } pub fn process < P > (& self) -> Process < P > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . nodes . borrow_mut () . push (id) ; Process { id , _phantom : PhantomData , } } pub fn cluster < C > (& self) -> Cluster < C > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . clusters . borrow_mut () . push (id) ; Cluster { id , _phantom : PhantomData , } } pub fn runtime_context (& self) -> RuntimeContext < 'a > { RuntimeContext { _phantom : PhantomData , } } pub fn cluster_members < C > (& self , cluster : & Cluster < C > ,) -> impl Quoted < 'a , & 'a Vec < u32 > > + Copy + 'a { ClusterIds { id : cluster . id , _phantom : PhantomData , } } pub fn cluster_self_id < C > (& self , cluster : & Cluster < C >) -> impl Quoted < 'a , u32 > + Copy + 'a { ClusterSelfId { id : cluster . id , _phantom : PhantomData , } } pub fn spin < L : Location > (& self , on : & L) -> Stream < 'a , () , Unbounded , NoTick , L > { Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Spin () , location_kind : on . id () , })) ,) } pub fn spin_batch < L : Location > (& self , on : & L , batch_size : impl Quoted < 'a , usize > + Copy + 'a ,) -> Stream < 'a , () , Bounded , Tick , L > { self . spin (on) . flat_map (q ! (move | _ | 0 .. batch_size)) . map (q ! (| _ | ())) . tick_batch () } pub fn source_stream < T , E : FuturesStream < Item = T > + Unpin , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Unbounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Stream (e . into ()) , location_kind : on . id () , })) ,) } pub fn source_iter < T , E : IntoIterator < Item = T > , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Bounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , })) ,) } pub fn singleton < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Singleton < 'a , T , Bounded , NoTick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Singleton :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,)))) ,) } pub fn singleton_first_tick < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Optional < 'a , T , Bounded , Tick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,) } pub fn source_interval < L : Location > (& self , on : & L , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , () , Unbounded , NoTick , L > { let interval = interval . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : on . id () , })) ,) } pub fn source_interval_delayed < L : Location > (& self , on : & L , delay : impl Quoted < 'a , Duration > + Copy + 'a , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , tokio :: time :: Instant , Unbounded , NoTick , L > { self . source_stream (on , q ! (tokio_stream :: wrappers :: IntervalStream :: new (tokio :: time :: interval_at (tokio :: time :: Instant :: now () + delay , interval))) ,) . tick_batch () . first () . latest () } pub fn cycle < S : CycleCollection < 'a > > (& self , on : & S :: Location) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , on . id ()) ,) } pub fn cycle_with_initial < S : CycleCollectionWithInitial < 'a > > (& self , on : & S :: Location , initial : S ,) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , initial , on . id ()) ,) } } } pub use builder :: FlowBuilder ; pub mod ir { pub use core :: panic ; pub use std :: cell :: RefCell ; pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow_lang :: graph :: FlatGraphBuilder ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: ToTokens ; pub use syn :: parse_quote ; pub use crate :: deploy :: Deploy ; pub use crate :: location :: LocationId ; pub use crate :: ir :: DebugExpr ; # [cfg (stageleft_macro)] impl From < syn :: Expr > for DebugExpr { fn from (expr : syn :: Expr) -> DebugExpr { DebugExpr (expr) } } # [cfg (stageleft_macro)] impl Deref for DebugExpr { type Target = syn :: Expr ; fn deref (& self) -> & Self :: Target { & self . 0 } } # [cfg (stageleft_macro)] impl ToTokens for DebugExpr { fn to_tokens (& self , tokens : & mut TokenStream) { self . 0 . to_tokens (tokens) ; } } # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugExpr { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "{}" , self . 0 . to_token_stream ()) } } pub use crate :: ir :: DebugInstantiate ; # [cfg (stageleft_macro)] impl < 'a > std :: fmt :: Debug for DebugInstantiate < 'a > { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<network instantiate>") } } pub use crate :: ir :: DebugPipelineFn ; # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugPipelineFn { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<function>") } } pub use crate :: ir :: HfPlusSource ; pub use crate :: ir :: HfPlusLeaf ; # [cfg (stageleft_macro)] impl < 'a > HfPlusLeaf < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . compile_network :: < D > (compile_env , s , nodes , clusters) ; } , seen_tees ,) } pub fn connect_network (self , seen_tees : & mut SeenTees < 'a >) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . connect_network (s) ; } , seen_tees ,) } pub fn transform_children (self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) -> HfPlusLeaf < 'a > { match self { HfPlusLeaf :: ForEach { f , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: ForEach { f , input } } HfPlusLeaf :: DestSink { sink , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: DestSink { sink , input } } HfPlusLeaf :: CycleSink { ident , location_kind , mut input , } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: CycleSink { ident , location_kind , input , } } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) { match self { HfPlusLeaf :: ForEach { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> for_each (# f) ; }) ; } HfPlusLeaf :: DestSink { sink , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink) ; }) ; } HfPlusLeaf :: CycleSink { ident , location_kind , input , } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; assert_eq ! (input_location_id , * location_id , "cycle_sink location mismatch") ; graph_builders . entry (* location_id) . or_default () . add_statement (parse_quote ! { # ident = # input_ident ; }) ; } } } } pub use crate :: ir :: HfPlusNode ; pub type SeenTees < 'a > = HashMap < * const RefCell < HfPlusNode < 'a > > , Rc < RefCell < HfPlusNode < 'a > > > > ; # [cfg (stageleft_macro)] impl < 'a > HfPlusNode < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (& mut self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) { self . transform_children (| n , s | n . compile_network :: < D > (compile_env , s , nodes , clusters) , seen_tees ,) ; if let HfPlusNode :: Network { from_location , to_location , instantiate_fn , .. } = self { let (sink_expr , source_expr , connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { let ((sink , source) , connect_fn) = match (from_location , to_location) { (LocationId :: Process (from) , LocationId :: Process (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: o2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Process (from) , LocationId :: Cluster (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: o2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Process (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: m2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Cluster (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: m2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } } ; (sink , source , connect_fn) } DebugInstantiate :: Finalized (_ , _ , _) => panic ! ("network already finalized") , } ; * instantiate_fn = DebugInstantiate :: Finalized (sink_expr , source_expr , connect_fn) ; } } pub fn connect_network (& mut self , seen_tees : & mut SeenTees < 'a >) { self . transform_children (| n , s | n . connect_network (s) , seen_tees) ; if let HfPlusNode :: Network { instantiate_fn , .. } = self { match instantiate_fn { DebugInstantiate :: Building () => panic ! ("network not built") , DebugInstantiate :: Finalized (_ , _ , ref connect_fn) => { connect_fn () ; } } } } pub fn transform_children (& mut self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) { match self { HfPlusNode :: Placeholder => { panic ! () ; } HfPlusNode :: Source { .. } => { } HfPlusNode :: CycleSource { .. } => { } HfPlusNode :: Tee { inner } => { if let Some (transformed) = seen_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { * inner = transformed . clone () ; } else { let transformed_cell = Rc :: new (RefCell :: new (HfPlusNode :: Placeholder)) ; seen_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , transformed_cell . clone () ,) ; let mut orig = inner . replace (HfPlusNode :: Placeholder) ; transform (& mut orig , seen_tees) ; * transformed_cell . borrow_mut () = orig ; * inner = transformed_cell ; } } HfPlusNode :: Persist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Unpersist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Delta (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Union (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossProduct (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossSingleton (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Join (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Difference (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: AntiJoin (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Map { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FlatMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Filter { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FilterMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Sort (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: DeferTick (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Enumerate (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Inspect { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Unique (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Fold { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FoldKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Reduce { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: ReduceKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Network { input , .. } => { transform (input . as_mut () , seen_tees) ; } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) -> (syn :: Ident , usize) { match self { HfPlusNode :: Placeholder => { panic ! () } HfPlusNode :: Persist (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let persist_id = * next_stmt_id ; * next_stmt_id += 1 ; let persist_ident = syn :: Ident :: new (& format ! ("stream_{}" , persist_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # persist_ident = # inner_ident -> persist ::<'static > () ; }) ; (persist_ident , location) } HfPlusNode :: Unpersist (_) => { panic ! ("Unpersist is a marker node and should have been optimized away. This is likely a compiler bug.") } HfPlusNode :: Delta (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let delta_id = * next_stmt_id ; * next_stmt_id += 1 ; let delta_ident = syn :: Ident :: new (& format ! ("stream_{}" , delta_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # delta_ident = # inner_ident -> multiset_delta () ; }) ; (delta_ident , location) } HfPlusNode :: Source { source , location_kind , } => { let source_id = * next_stmt_id ; * next_stmt_id += 1 ; let source_ident = syn :: Ident :: new (& format ! ("stream_{}" , source_id) , Span :: call_site ()) ; let source_stmt = match source { HfPlusSource :: Stream (expr) => { parse_quote ! { # source_ident = source_stream (# expr) ; } } HfPlusSource :: Iter (expr) => { parse_quote ! { # source_ident = source_iter (# expr) ; } } HfPlusSource :: Interval (expr) => { parse_quote ! { # source_ident = source_interval (# expr) ; } } HfPlusSource :: Spin () => { parse_quote ! { # source_ident = spin () ; } } } ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; graph_builders . entry (* location_id) . or_default () . add_statement (source_stmt) ; (source_ident , * location_id) } HfPlusNode :: CycleSource { ident , location_kind , } => { let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; (ident . clone () , * location_id) } HfPlusNode :: Tee { inner } => { if let Some (ret) = built_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { ret . clone () } else { let (inner_ident , inner_location_id) = inner . borrow () . emit (graph_builders , built_tees , next_stmt_id) ; let tee_id = * next_stmt_id ; * next_stmt_id += 1 ; let tee_ident = syn :: Ident :: new (& format ! ("stream_{}" , tee_id) , Span :: call_site ()) ; let builder = graph_builders . entry (inner_location_id) . or_default () ; builder . add_statement (parse_quote ! { # tee_ident = # inner_ident -> tee () ; }) ; built_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , (tee_ident . clone () , inner_location_id) ,) ; (tee_ident , inner_location_id) } } HfPlusNode :: Union (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "union inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let union_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # union_ident = union () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [0] # union_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # union_ident ; }) ; (union_ident , left_location_id) } HfPlusNode :: CrossSingleton (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "cross_singleton inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let cross_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # cross_ident = cross_singleton () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [input] # cross_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [single] # cross_ident ; }) ; (cross_ident , left_location_id) } HfPlusNode :: CrossProduct (..) | HfPlusNode :: Join (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: CrossProduct (..)) { parse_quote ! (cross_join_multiset) } else { parse_quote ! (join_multiset) } ; let (HfPlusNode :: CrossProduct (left , right) | HfPlusNode :: Join (left , right)) = self else { unreachable ! () } ; let (left_inner , left_was_persist) = if let HfPlusNode :: Persist (left) = left . as_ref () { (left , true) } else { (left , false) } ; let (right_inner , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left_inner . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right_inner . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "join / cross product inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; match (left_was_persist , right_was_persist) { (true , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'static > () ; }) ; } (true , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'tick > () ; }) ; } (false , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } (false , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } } ; builder . add_statement (parse_quote ! { # left_ident -> [0] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Difference (..) | HfPlusNode :: AntiJoin (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Difference (..)) { parse_quote ! (difference_multiset) } else { parse_quote ! (anti_join_multiset) } ; let (HfPlusNode :: Difference (left , right) | HfPlusNode :: AntiJoin (left , right)) = self else { unreachable ! () } ; let (right , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "difference / anti join inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; if right_was_persist { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } else { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } builder . add_statement (parse_quote ! { # left_ident -> [pos] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [neg] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Map { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let map_id = * next_stmt_id ; * next_stmt_id += 1 ; let map_ident = syn :: Ident :: new (& format ! ("stream_{}" , map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # map_ident = # input_ident -> map (# f) ; }) ; (map_ident , input_location_id) } HfPlusNode :: FlatMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let flat_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let flat_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , flat_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # flat_map_ident = # input_ident -> flat_map (# f) ; }) ; (flat_map_ident , input_location_id) } HfPlusNode :: Filter { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_ident = # input_ident -> filter (# f) ; }) ; (filter_ident , input_location_id) } HfPlusNode :: FilterMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_map_ident = # input_ident -> filter_map (# f) ; }) ; (filter_map_ident , input_location_id) } HfPlusNode :: Sort (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sort_id = * next_stmt_id ; * next_stmt_id += 1 ; let sort_ident = syn :: Ident :: new (& format ! ("stream_{}" , sort_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # sort_ident = # input_ident -> sort () ; }) ; (sort_ident , input_location_id) } HfPlusNode :: DeferTick (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let defer_tick_id = * next_stmt_id ; * next_stmt_id += 1 ; let defer_tick_ident = syn :: Ident :: new (& format ! ("stream_{}" , defer_tick_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # defer_tick_ident = # input_ident -> defer_tick_lazy () ; }) ; (defer_tick_ident , input_location_id) } HfPlusNode :: Enumerate (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let enumerate_id = * next_stmt_id ; * next_stmt_id += 1 ; let enumerate_ident = syn :: Ident :: new (& format ! ("stream_{}" , enumerate_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # enumerate_ident = # input_ident -> enumerate () ; }) ; (enumerate_ident , input_location_id) } HfPlusNode :: Inspect { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let inspect_id = * next_stmt_id ; * next_stmt_id += 1 ; let inspect_ident = syn :: Ident :: new (& format ! ("stream_{}" , inspect_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # inspect_ident = # input_ident -> inspect (# f) ; }) ; (inspect_ident , input_location_id) } HfPlusNode :: Unique (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let unique_id = * next_stmt_id ; * next_stmt_id += 1 ; let unique_ident = syn :: Ident :: new (& format ! ("stream_{}" , unique_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # unique_ident = # input_ident -> unique ::<'tick > () ; }) ; (unique_ident , input_location_id) } HfPlusNode :: Fold { .. } | HfPlusNode :: FoldKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Fold { .. }) { parse_quote ! (fold) } else { parse_quote ! (fold_keyed) } ; let (HfPlusNode :: Fold { init , acc , input } | HfPlusNode :: FoldKeyed { init , acc , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let fold_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'static > (# init , # acc) ; }) ; } else { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'tick > (# init , # acc) ; }) ; } (fold_ident , input_location_id) } HfPlusNode :: Reduce { .. } | HfPlusNode :: ReduceKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Reduce { .. }) { parse_quote ! (reduce) } else { parse_quote ! (reduce_keyed) } ; let (HfPlusNode :: Reduce { f , input } | HfPlusNode :: ReduceKeyed { f , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let reduce_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'static > (# f) ; }) ; } else { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'tick > (# f) ; }) ; } (reduce_ident , input_location_id) } HfPlusNode :: Network { from_location : _ , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input , } => { let (sink_expr , source_expr , _connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { panic ! ("Expected the network to be finalized") } DebugInstantiate :: Finalized (sink , source , connect_fn) => { (sink , source , connect_fn) } } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sender_builder = graph_builders . entry (input_location_id) . or_default () ; if let Some (serialize_pipeline) = serialize_pipeline { sender_builder . add_statement (parse_quote ! { # input_ident -> # serialize_pipeline -> dest_sink (# sink_expr) ; }) ; } else { sender_builder . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink_expr) ; }) ; } let to_id = match to_location { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let receiver_builder = graph_builders . entry (* to_id) . or_default () ; let receiver_stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let receiver_stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , receiver_stream_id) , Span :: call_site ()) ; if let Some (deserialize_pipeline) = deserialize_pipeline { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) -> # deserialize_pipeline ; }) ; } else { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) ; }) ; } (receiver_stream_ident , * to_id) } } } } } pub mod persist_pullup { pub use std :: cell :: RefCell ; pub use std :: collections :: HashSet ; pub use std :: ops :: Deref ; pub use crate :: ir :: * ; pub fn persist_pullup_node < 'a > (node : & mut HfPlusNode < 'a > , seen_tees : & mut SeenTees < 'a > , persist_pulled_tees : & mut HashSet < * const RefCell < HfPlusNode < 'a > > > ,) { node . transform_children (| n , s | persist_pullup_node (n , s , persist_pulled_tees) , seen_tees ,) ; match node { HfPlusNode :: Unpersist (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Unpersist (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Delta (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Delta (HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Tee { inner } => { if persist_pulled_tees . contains (& (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >)) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } else { let inner_borrow = inner . borrow () ; if let HfPlusNode :: Persist (_) = inner_borrow . deref () { drop (inner_borrow) ; persist_pulled_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >) ; if let HfPlusNode :: Persist (box behind_persist) = inner . replace (HfPlusNode :: Placeholder) { * inner . borrow_mut () = behind_persist ; } else { unreachable ! () } * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } } } HfPlusNode :: Map { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Map { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Map { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: FlatMap { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: FlatMap { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: FlatMap { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Filter { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Filter { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Filter { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Network { input : box HfPlusNode :: Persist (_) , .. } => { if let HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Union (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Union (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Union (left , right))) ; } else { unreachable ! () } } HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: CrossProduct (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,) ,)))) ; } else { unreachable ! () } } HfPlusNode :: Join (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Join (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: Join (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,))))) ; } else { unreachable ! () } } _ => { } } } pub fn persist_pullup (ir : Vec < HfPlusLeaf >) -> Vec < HfPlusLeaf > { let mut seen_tees = Default :: default () ; let mut persist_pulled_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| n , s | persist_pullup_node (n , s , & mut persist_pulled_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn persist_pullup_through_map () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } # [test] fn persist_pullup_behind_tee () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; let before_tee = flow . source_iter (& process , q ! (0 .. 10)) . tick_batch () . persist () ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } } } pub mod profiler { pub use std :: cell :: RefCell ; pub use hydroflow :: futures :: channel :: mpsc :: UnboundedSender ; pub use stageleft :: * ; pub use crate as hydroflow_plus ; pub use crate :: ir :: * ; pub use crate :: RuntimeContext ; pub fn increment_counter (count : & mut u64) { * count += 1 ; } pub fn quoted_any_fn < 'a , F : Fn (& usize) + 'a , Q : IntoQuotedMut < 'a , F > > (q : Q) -> Q { q } # [doc = " Add a profiling node before each node to count the cardinality of its input"] pub fn add_profiling_node < 'a > (node : & mut HfPlusNode < 'a > , _context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > , id : & mut u32 , seen_tees : & mut SeenTees < 'a > ,) { let my_id = * id ; * id += 1 ; node . transform_children (| node , seen_tees | { add_profiling_node (node , _context , counters , counter_queue , id , seen_tees) } , seen_tees ,) ; let orig_node = std :: mem :: replace (node , HfPlusNode :: Placeholder) ; * node = HfPlusNode :: Inspect { f : quoted_any_fn (q ! ({ counter_queue . borrow () . unbounded_send ((my_id as usize , counters . borrow () [my_id as usize])) . unwrap () ; counters . borrow_mut () [my_id as usize] = 0 ; move | _ | { hydroflow_plus :: profiler :: increment_counter (& mut counters . borrow_mut () [my_id as usize] ,) ; } })) . splice () . into () , input : Box :: new (orig_node) , } } # [doc = " Count the cardinality of each input and periodically output to a file"] pub fn profiling < 'a > (ir : Vec < HfPlusLeaf < 'a > > , context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > ,) -> Vec < HfPlusLeaf < 'a > > { let mut id = 0 ; let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | { add_profiling_node (node , context , counters , counter_queue , & mut id , seen_tees) } , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn profiler_wrapping_all_operators () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let runtime_context = flow . runtime_context () ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (& built . ir ()) ; let counters = RuntimeData :: new ("Fake") ; let counter_queue = RuntimeData :: new ("Fake") ; let pushed_down = built . with_default_optimize () . optimize_with (| ir | super :: profiling (ir , runtime_context , counters , counter_queue)) ; insta :: assert_debug_snapshot ! (& pushed_down . ir ()) ; let _ = pushed_down . compile_no_network :: < MultiGraph > () ; } } } pub mod properties { pub use std :: collections :: HashSet ; pub use stageleft :: * ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , SeenTees } ; pub use crate :: properties :: PropertyDatabase ; # [doc = " Allows us to convert the hydroflow datatype for folds to a binary operation for the algebra"] # [doc = " property tests."] # [allow (dead_code)] pub fn convert_hf_to_binary < I , A : Default , F : Fn (& mut A , I) > (f : F) -> impl Fn (I , I) -> A { move | a , b | { let mut acc = Default :: default () ; f (& mut acc , a) ; f (& mut acc , b) ; acc } } # [cfg (stageleft_macro)] impl PropertyDatabase { # [doc = " Tags the expression as commutative."] pub fn add_commutative_tag < 'a , I , A , F : Fn (& mut A , I) , Q : Quoted < 'a , F > + Clone > (& mut self , expr : Q ,) -> Q { let expr_clone = expr . clone () ; self . commutative . insert (expr_clone . splice ()) ; expr } pub fn is_tagged_commutative (& self , expr : & syn :: Expr) -> bool { self . commutative . contains (expr) } } pub fn properties_optimize_node < 'a > (node : & mut HfPlusNode < 'a > , db : & PropertyDatabase , seen_tees : & mut SeenTees < 'a > ,) { node . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , seen_tees ,) ; match node { HfPlusNode :: ReduceKeyed { f , .. } if db . is_tagged_commutative (& f . 0) => { dbg ! ("IDENTIFIED COMMUTATIVE OPTIMIZATION for {:?}" , & f) ; } _ => { } } } pub fn properties_optimize < 'a > (ir : Vec < HfPlusLeaf < 'a > > , db : & PropertyDatabase ,) -> Vec < HfPlusLeaf < 'a > > { let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use super :: * ; use crate :: deploy :: SingleProcessGraph ; use crate :: FlowBuilder ; # [test] fn test_property_database () { let mut db = PropertyDatabase :: default () ; assert ! (! db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; let _ = db . add_commutative_tag (q ! (| a : & mut i32 , b : i32 | * a += b)) ; assert ! (db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; } # [test] fn test_property_optimized () { let flow = FlowBuilder :: new () ; let mut database = PropertyDatabase :: default () ; let process = flow . process :: < () > () ; let counter_func = q ! (| count : & mut i32 , _ | * count += 1) ; let _ = database . add_commutative_tag (counter_func) ; flow . source_iter (& process , q ! (vec ! [])) . map (q ! (| string : String | (string , ()))) . tick_batch () . fold_keyed (q ! (|| 0) , counter_func) . all_ticks () . for_each (q ! (| (string , count) | println ! ("{}: {}" , string , count))) ; let built = flow . finalize () . optimize_with (| ir | properties_optimize (ir , & database)) . with_default_optimize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let _ = built . compile_no_network :: < SingleProcessGraph > () ; } } } pub use crate :: RuntimeContext ; # [cfg (stageleft_macro)] impl Copy for RuntimeContext < '_ > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Context > for RuntimeContext < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (quote ! (& context))) } } pub use crate :: HfCompiled ; # [cfg (stageleft_macro)] impl < 'a , ID > HfCompiled < 'a , ID > { pub fn hydroflow_ir (& self) -> & BTreeMap < usize , HydroflowGraph > { & self . hydroflow_ir } } # [cfg (stageleft_macro)] impl < 'a > HfCompiled < 'a , usize > { pub fn with_dynamic_id (self , id : impl Quoted < 'a , usize >) -> HfBuiltWithId < 'a > { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; let mut conditioned_tokens = None ; for (subgraph_id , flat_graph) in self . hydroflow_ir { let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; let my_extra_stmts = self . extra_stmts . get (& subgraph_id) . cloned () . unwrap_or_default () ; if let Some (conditioned_tokens) = conditioned_tokens . as_mut () { * conditioned_tokens = syn :: parse_quote ! { # conditioned_tokens else if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } } ; } else { conditioned_tokens = Some (syn :: parse_quote ! { if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } }) ; } } let conditioned_tokens : TokenStream = conditioned_tokens . unwrap () ; let id = id . splice () ; HfBuiltWithId { tokens : syn :: parse_quote ! ({ let __given_id = # id ; # conditioned_tokens else { panic ! ("Invalid node id: {}" , __given_id) ; } }) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfCompiled < 'a , () > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfCompiled < 'a , () > { fn to_tokens (mut self) -> (Option < TokenStream > , Option < TokenStream >) { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; if self . hydroflow_ir . len () != 1 { panic ! ("Expected exactly one subgraph in the Hydroflow IR") ; } let flat_graph = self . hydroflow_ir . remove (& 0) . unwrap () ; let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; (None , Some (tokens)) } } pub use crate :: HfBuiltWithId ; # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfBuiltWithId < 'a > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfBuiltWithId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (self . tokens)) } }
[INFO] [stdout]   |
[INFO] [stdout] help: ...otherwise replace it with an invocation of macro `deref`
[INFO] [stdout]   |
[INFO] [stdout] 1 - pub use std :: collections :: BTreeMap ; pub use std :: marker :: PhantomData ; pub use hydroflow :: scheduled :: context :: Context ; pub use hydroflow :: scheduled :: graph :: Hydroflow ; pub use hydroflow :: * ; pub use lang :: graph :: { partition_graph , HydroflowGraph } ; pub use proc_macro2 :: TokenStream ; pub use quote :: quote ; pub use stageleft :: runtime_support :: FreeVariable ; pub use stageleft :: Quoted ; pub mod runtime_support { pub use bincode ; } pub mod stream { pub use std :: cell :: RefCell ; pub use std :: hash :: Hash ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow :: bytes :: Bytes ; pub use hydroflow :: futures :: Sink ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: quote ; pub use serde :: de :: DeserializeOwned ; pub use serde :: Serialize ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use syn :: parse_quote ; pub use crate :: builder :: { ClusterIds , FlowLeaves } ; pub use crate :: cycle :: { CycleCollection , CycleComplete } ; pub use crate :: ir :: { DebugInstantiate , HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { CanSend , Location , LocationId } ; pub use crate :: { Cluster , Optional , Singleton } ; pub use crate :: stream :: Unbounded ; pub use crate :: stream :: Bounded ; pub use crate :: stream :: NoTick ; pub use crate :: stream :: Tick ; pub use crate :: stream :: Stream ; # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Stream { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Stream < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Stream { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , C , N > > ,) -> Stream < 'a , (T , O) , W , C , N > where O : Clone , { let other : Optional < 'a , O , Bounded , C , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn cross_product < O > (self , other : Stream < 'a , O , W , C , N >) -> Stream < 'a , (T , O) , W , C , N > where T : Clone , O : Clone , { if self . location_kind != other . location_kind { panic ! ("cross_product must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossProduct (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn union (self , other : Stream < 'a , T , W , C , N >) -> Stream < 'a , T , W , C , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn dest_sink < S : Unpin + Sink < T > + 'a > (self , sink : impl Quoted < 'a , S >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: DestSink { sink : sink . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn first (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } # [doc = " Allow this stream through if the other stream has elements, otherwise the output is empty."] pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } # [doc = " Allow this stream through if the other stream is empty, otherwise the output is empty."] pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn enumerate (self) -> Stream < 'a , (usize , T) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Enumerate (Box :: new (self . ir_node . into_inner ())) ,) } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn sort (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Ord , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Sort (Box :: new (self . ir_node . into_inner ())) ,) } pub fn count (self) -> Singleton < 'a , usize , Bounded , Tick , N > { self . fold (q ! (|| 0usize) , q ! (| count , _ | * count += 1)) } pub fn delta (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } pub fn unique (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Eq + Hash , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unique (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn tick_batch (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_prefix (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { self . tick_batch () . persist () } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn for_each < F : Fn (T) + 'a > (self , f : impl IntoQuotedMut < 'a , F >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: ForEach { input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , f : f . splice () . into () , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Unbounded , NoTick , N > { pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . tick_batch () . continue_if (samples . first ()) . all_ticks () } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Unbounded , NoTick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , C , N : Location > Stream < 'a , T , Bounded , C , N > { pub fn filter_not_in (self , other : Stream < 'a , T , Bounded , C , N >) -> Stream < 'a , T , Bounded , C , N > where T : Eq + Hash , { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Difference (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Stream < 'a , & T , W , C , N > { pub fn cloned (self) -> Stream < 'a , T , W , C , N > { self . map (q ! (| d | d . clone ())) } } # [cfg (stageleft_macro)] impl < 'a , K , V1 , W , C , N : Location > Stream < 'a , (K , V1) , W , C , N > { pub fn join < W2 , V2 > (self , n : Stream < 'a , (K , V2) , W2 , C , N > ,) -> Stream < 'a , (K , (V1 , V2)) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Join (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } pub fn anti_join < W2 > (self , n : Stream < 'a , K , W2 , C , N >) -> Stream < 'a , (K , V1) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("anti_join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: AntiJoin (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , K : Eq + Hash , V , N : Location > Stream < 'a , (K , V) , Bounded , Tick , N > { pub fn fold_keyed < A , I : Fn () -> A + 'a , F : Fn (& mut A , V) + 'a > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , A) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FoldKeyed { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce_keyed < F : Fn (& mut V , V) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , V) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: ReduceKeyed { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } pub fn get_this_crate () -> TokenStream { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , Span :: call_site ()) ; quote ! { # ident } } } } pub fn serialize_bincode < T : Serialize > (is_demux : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if is_demux { parse_quote ! { map (| (id , data) | { (id , # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into ()) }) } } else { parse_quote ! { map (| data | { # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into () }) } } } pub fn deserialize_bincode < T : DeserializeOwned > (tagged : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if tagged { parse_quote ! { map (| res | { let (id , b) = res . unwrap () ; (id , # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& b) . unwrap ()) }) } } else { parse_quote ! { map (| res | { # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& res . unwrap ()) . unwrap () }) } } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn send_bincode < N2 : Location , CoreType > (self , other : & N2 ,) -> Stream < 'a , N :: Out < CoreType > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T > , CoreType : Serialize + DeserializeOwned , { let serialize_pipeline = Some (serialize_bincode :: < CoreType > (N :: is_demux ())) ; let deserialize_pipeline = Some (deserialize_bincode :: < CoreType > (N :: is_tagged ())) ; Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bytes < N2 : Location > (self , other : & N2 ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T > , { Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline : None , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline : if N :: is_tagged () { Some (parse_quote ! (map (| (id , b) | (id , b . unwrap () . freeze ())))) } else { Some (parse_quote ! (map (| b | b . unwrap () . freeze ()))) } , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bincode_interleaved < N2 : Location , Tag , CoreType > (self , other : & N2 ,) -> Stream < 'a , CoreType , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T , Out < CoreType > = (Tag , CoreType) > , CoreType : Serialize + DeserializeOwned , { self . send_bincode :: < N2 , CoreType > (other) . map (q ! (| (_ , b) | b)) } pub fn send_bytes_interleaved < N2 : Location , Tag > (self , other : & N2 ,) -> Stream < 'a , Bytes , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T , Out < Bytes > = (Tag , Bytes) > , { self . send_bytes :: < N2 > (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bincode < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < T > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) > , T : Clone + Serialize + DeserializeOwned , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bincode (other) } pub fn broadcast_bincode_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , T , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) , Out < T > = (Tag , T) > + 'a , T : Clone + Serialize + DeserializeOwned , { self . broadcast_bincode (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bytes < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) > + 'a , T : Clone , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bytes (other) } pub fn broadcast_bytes_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , Bytes , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) , Out < Bytes > = (Tag , Bytes) > + 'a , T : Clone , { self . broadcast_bytes (other) . map (q ! (| (_ , b) | b)) } } } pub use stream :: { Bounded , NoTick , Stream , Tick , Unbounded } ; pub mod singleton { pub use std :: cell :: RefCell ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use crate :: builder :: FlowLeaves ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial , CycleComplete } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: Stream ; pub use crate :: singleton :: CrossResult ; # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Singleton < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Singleton :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } pub use crate :: singleton :: Singleton ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Singleton { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleComplete < 'a > for Singleton < 'a , T , Bounded , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleCollectionWithInitial < 'a > for Singleton < 'a , T , Bounded , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , initial : Self , l : LocationId ,) -> Self { Singleton :: new (l , ir_leaves , HfPlusNode :: Union (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , }) , initial . ir_node . into_inner () . into () ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Singleton < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Singleton { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , U , W , C , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (Self :: other_ir_node (other)) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Singleton < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CrossSingleton (Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , Box :: new (HfPlusNode :: Unpersist (Box :: new (Self :: other_ir_node (other)))) ,))) ,) } } pub use crate :: singleton :: Optional ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Optional { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } pub fn some (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: new (singleton . location_kind , singleton . ir_leaves , singleton . ir_node . into_inner () ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > From < Singleton < 'a , T , W , C , N > > for Optional < 'a , T , W , C , N > { fn from (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: some (singleton) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Optional < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Optional { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn into_stream (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , Tick , N > > ,) -> Optional < 'a , (T , O) , Bounded , Tick , N > where O : Clone , { let other : Optional < 'a , O , Bounded , Tick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn union (self , other : Optional < 'a , T , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Optional < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_samples (self) -> Stream < 'a , T , Unbounded , NoTick , N > { self . latest_tick () . all_ticks () } pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . latest_tick () . continue_if (samples . first ()) . latest () . tick_samples () } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Unbounded , NoTick , N > > ,) -> Optional < 'a , (T , O) , Unbounded , NoTick , N > where O : Clone , { let other : Optional < 'a , O , Unbounded , NoTick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } self . latest_tick () . cross_singleton (other . latest_tick ()) . latest () } } } pub use singleton :: { Optional , Singleton } ; pub mod location { pub use std :: marker :: PhantomData ; pub use crate :: location :: LocationId ; pub use crate :: location :: Location ; pub use crate :: location :: Process ; # [cfg (stageleft_macro)] impl < P > Clone for Process < P > { fn clone (& self) -> Self { Process { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < P > Location for Process < P > { fn id (& self) -> LocationId { LocationId :: Process (self . id) } } pub use crate :: location :: Cluster ; # [cfg (stageleft_macro)] impl < C > Clone for Cluster < C > { fn clone (& self) -> Self { Cluster { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < C > Location for Cluster < C > { fn id (& self) -> LocationId { LocationId :: Cluster (self . id) } } pub use crate :: location :: CanSend ; # [cfg (stageleft_macro)] impl < P1 , P2 > CanSend < Process < P2 > > for Process < P1 > { type In < T > = T ; type Out < T > = T ; fn is_demux () -> bool { false } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < P1 , C2 > CanSend < Cluster < C2 > > for Process < P1 > { type In < T > = (u32 , T) ; type Out < T > = T ; fn is_demux () -> bool { true } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < C1 , P2 > CanSend < Process < P2 > > for Cluster < C1 > { type In < T > = T ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { false } fn is_tagged () -> bool { true } } # [cfg (stageleft_macro)] impl < C1 , C2 > CanSend < Cluster < C2 > > for Cluster < C1 > { type In < T > = (u32 , T) ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { true } fn is_tagged () -> bool { true } } } pub use location :: { Cluster , Process } ; pub mod deploy { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use stageleft :: Quoted ; pub mod graphs { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use super :: { LocalDeploy , Node , ProcessSpec } ; pub use crate :: deploy :: graphs :: SingleProcessGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for SingleProcessGraph { type Process = SingleNode ; type Cluster = SingleNode ; type Meta = () ; type GraphId = () ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { SingleNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { SingleNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , SingleProcessGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> SingleNode { SingleNode { } } } pub use crate :: deploy :: graphs :: SingleNode ; # [cfg (stageleft_macro)] impl Node for SingleNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } pub use crate :: deploy :: graphs :: MultiGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for MultiGraph { type Process = MultiNode ; type Cluster = MultiNode ; type Meta = () ; type GraphId = usize ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { MultiNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { MultiNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , MultiGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> MultiNode { MultiNode { } } } pub use crate :: deploy :: graphs :: MultiNode ; # [cfg (stageleft_macro)] impl Node for MultiNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } } pub use graphs :: * ; pub use crate :: deploy :: LocalDeploy ; pub use crate :: deploy :: Deploy ; # [cfg (stageleft_macro)] impl < 'a , T : Deploy < 'a , Process = N , Cluster = C , Meta = M , GraphId = R > , N : Node < Meta = M > , C : Node < Meta = M > , M : Default , R , > LocalDeploy < 'a > for T { type Process = N ; type Cluster = C ; type Meta = M ; type GraphId = R ; fn has_trivial_node () -> bool { < T as Deploy < 'a > > :: has_trivial_node () } fn trivial_process (id : usize) -> Self :: Process { < T as Deploy < 'a > > :: trivial_process (id) } fn trivial_cluster (id : usize) -> Self :: Cluster { < T as Deploy < 'a > > :: trivail_cluster (id) } } pub use crate :: deploy :: ProcessSpec ; pub use crate :: deploy :: ClusterSpec ; pub use crate :: deploy :: Node ; } pub use deploy :: { ClusterSpec , Deploy , ProcessSpec } ; pub mod cycle { pub use std :: marker :: PhantomData ; pub use crate :: builder :: FlowLeaves ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: cycle :: CycleComplete ; pub use crate :: cycle :: CycleCollection ; pub use crate :: cycle :: CycleCollectionWithInitial ; pub use crate :: cycle :: HfCycle ; # [cfg (stageleft_macro)] impl < 'a , S : CycleComplete < 'a > > HfCycle < 'a , S > { pub fn complete (self , stream : S) { let ident = self . ident ; S :: complete (stream , ident) } } } pub use cycle :: HfCycle ; pub mod builder { pub use std :: cell :: RefCell ; pub use std :: collections :: HashMap ; pub use std :: marker :: PhantomData ; pub use std :: rc :: Rc ; pub use std :: time :: Duration ; pub use hydroflow :: futures :: stream :: Stream as FuturesStream ; pub use hydroflow :: { tokio , tokio_stream } ; pub use internal :: TokenStream ; pub use proc_macro2 :: Span ; pub use quote :: quote ; pub use runtime_support :: FreeVariable ; pub use stageleft :: * ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Cluster , Location , LocationId , Process } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: { HfCycle , Optional , RuntimeContext , Singleton , Stream } ; pub mod built { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use hydroflow_lang :: graph :: { eliminate_extra_unions_tees , HydroflowGraph } ; pub use super :: deploy :: { DeployFlow , DeployResult } ; pub use crate :: deploy :: { ClusterSpec , Deploy , LocalDeploy , ProcessSpec } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Cluster , Process } ; pub use crate :: HfCompiled ; pub use crate :: builder :: built :: BuiltFlow ; # [cfg (stageleft_macro)] impl < 'a > Drop for BuiltFlow < 'a > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped BuiltFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn ir (& self) -> & Vec < HfPlusLeaf < 'a > > { & self . ir } pub fn optimize_with (mut self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> BuiltFlow < 'a > { self . used = true ; BuiltFlow { ir : f (std :: mem :: take (& mut self . ir)) , processes : std :: mem :: take (& mut self . processes) , clusters : std :: mem :: take (& mut self . clusters) , used : false , _phantom : PhantomData , } } } pub fn build_inner (ir : & mut Vec < HfPlusLeaf >) -> BTreeMap < usize , HydroflowGraph > { let mut builders = BTreeMap :: new () ; let mut built_tees = HashMap :: new () ; let mut next_stmt_id = 0 ; for leaf in ir { leaf . emit (& mut builders , & mut built_tees , & mut next_stmt_id) ; } builders . into_iter () . map (| (k , v) | { let (mut flat_graph , _ , _) = v . build () ; eliminate_extra_unions_tees (& mut flat_graph) ; (k , flat_graph) }) . collect () } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn compile_no_network < D : LocalDeploy < 'a > > (mut self) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; HfCompiled { hydroflow_ir : build_inner (& mut self . ir) , extra_stmts : BTreeMap :: new () , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> BuiltFlow < 'a > { self . optimize_with (crate :: persist_pullup :: persist_pullup) } fn into_deploy < D : LocalDeploy < 'a > > (mut self) -> DeployFlow < 'a , D > { self . used = true ; let processes = if D :: has_trivial_node () { self . processes . iter () . map (| id | (* id , D :: trivial_process (* id))) . collect () } else { HashMap :: new () } ; let clusters = if D :: has_trivial_node () { self . clusters . iter () . map (| id | (* id , D :: trivial_cluster (* id))) . collect () } else { HashMap :: new () } ; DeployFlow { ir : std :: mem :: take (& mut self . ir) , nodes : processes , clusters , used : false , _phantom : PhantomData , } } pub fn with_process < P , D : LocalDeploy < 'a > > (self , process : & Process < P > , spec : impl ProcessSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_process (process , spec) } pub fn with_cluster < C , D : LocalDeploy < 'a > > (self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_cluster (cluster , spec) } pub fn compile < D : Deploy < 'a > + 'a > (self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . into_deploy :: < D > () . compile (env) } pub fn deploy < D : Deploy < 'a , CompileEnv = () > + 'a > (self , env : & mut D :: InstantiateEnv ,) -> DeployResult < 'a , D > { self . into_deploy :: < D > () . deploy (env) } } } pub mod deploy { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use proc_macro2 :: Span ; pub use stageleft :: Quoted ; pub use super :: built :: build_inner ; pub use crate :: deploy :: { LocalDeploy , Node } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: { Cluster , ClusterSpec , Deploy , HfCompiled , Process , ProcessSpec } ; pub use crate :: builder :: deploy :: DeployFlow ; # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > Drop for DeployFlow < 'a , D > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped DeployFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > DeployFlow < 'a , D > { pub fn with_process < P > (mut self , process : & Process < P > , spec : impl ProcessSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < P > () . to_string () ; self . nodes . insert (process . id , spec . build (process . id , & tag_name)) ; self } pub fn with_cluster < C > (mut self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < C > () . to_string () ; self . clusters . insert (cluster . id , spec . build (cluster . id , & tag_name)) ; self } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployFlow < 'a , D > { pub fn compile (mut self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; let mut seen_tees : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | leaf . compile_network :: < D > (env , & mut seen_tees , & self . nodes , & self . clusters)) . collect () ; let extra_stmts = self . extra_stmts (env) ; HfCompiled { hydroflow_ir : build_inner (& mut ir_leaves_networked) , extra_stmts , _phantom : PhantomData , } } fn extra_stmts (& self , env : & < D as Deploy < 'a > > :: CompileEnv) -> BTreeMap < usize , Vec < syn :: Stmt > > { let all_locations_count = self . nodes . len () + self . clusters . len () ; let mut extra_stmts : BTreeMap < usize , Vec < syn :: Stmt > > = BTreeMap :: new () ; for & c_id in self . clusters . keys () { let self_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , c_id) , Span :: call_site () ,) ; let self_id_expr = D :: cluster_self_id (env) . splice () ; extra_stmts . entry (c_id) . or_default () . push (syn :: parse_quote ! { let # self_id_ident = # self_id_expr ; }) ; for other_location in 0 .. all_locations_count { let other_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , c_id) , Span :: call_site () ,) ; let other_id_expr = D :: cluster_ids (env , c_id) . splice () ; extra_stmts . entry (other_location) . or_default () . push (syn :: parse_quote ! { let # other_id_ident = # other_id_expr ; }) ; } } extra_stmts } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a , CompileEnv = () > > DeployFlow < 'a , D > { # [must_use] pub fn deploy (mut self , env : & mut D :: InstantiateEnv) -> DeployResult < 'a , D > { self . used = true ; let mut seen_tees_instantiate : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | { leaf . compile_network :: < D > (& () , & mut seen_tees_instantiate , & self . nodes , & self . clusters ,) }) . collect () ; let mut compiled = build_inner (& mut ir_leaves_networked) ; let mut extra_stmts = self . extra_stmts (& ()) ; let mut meta = D :: Meta :: default () ; let (mut processes , mut clusters) = (std :: mem :: take (& mut self . nodes) . into_iter () . map (| (node_id , node) | { node . instantiate (env , & mut meta , compiled . remove (& node_id) . unwrap () , extra_stmts . remove (& node_id) . unwrap_or_default () ,) ; (node_id , node) }) . collect :: < HashMap < _ , _ > > () , std :: mem :: take (& mut self . clusters) . into_iter () . map (| (cluster_id , cluster) | { cluster . instantiate (env , & mut meta , compiled . remove (& cluster_id) . unwrap () , extra_stmts . remove (& cluster_id) . unwrap_or_default () ,) ; (cluster_id , cluster) }) . collect :: < HashMap < _ , _ > > () ,) ; for node in processes . values_mut () { node . update_meta (& meta) ; } for cluster in clusters . values_mut () { cluster . update_meta (& meta) ; } let mut seen_tees_connect = HashMap :: new () ; for leaf in ir_leaves_networked { leaf . connect_network (& mut seen_tees_connect) ; } DeployResult { processes , clusters , } } } pub use crate :: builder :: deploy :: DeployResult ; # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployResult < 'a , D > { pub fn get_process < P > (& self , p : & Process < P >) -> & D :: Process { let id = match p . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . processes . get (& id) . unwrap () } pub fn get_cluster < C > (& self , c : & Cluster < C >) -> & D :: Cluster { let id = match c . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . clusters . get (& id) . unwrap () } } } # [doc = " Tracks the leaves of the dataflow IR. This is referenced by"] # [doc = " `Stream` and `HfCycle` to build the IR. The inner option will"] # [doc = " be set to `None` when this builder is finalized."] pub type FlowLeaves < 'a > = Rc < RefCell < Option < Vec < HfPlusLeaf < 'a > > > > > ; pub use crate :: builder :: ClusterIds ; # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Vec < u32 > > for ClusterIds < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , & 'a Vec < u32 > > for ClusterIds < 'a > { } # [derive (Copy , Clone)] pub struct ClusterSelfId < 'a > { pub id : usize , pub _phantom : PhantomData < & 'a mut & 'a u32 > , } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < u32 > for ClusterSelfId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , u32 > for ClusterSelfId < 'a > { } pub use crate :: builder :: FlowBuilder ; # [cfg (stageleft_macro)] impl < 'a > Drop for FlowBuilder < 'a > { fn drop (& mut self) { if ! self . finalized { panic ! ("Dropped FlowBuilder without finalizing, you may have forgotten to call `with_default_optimize`, `optimize_with`, or `finalize`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > QuotedContext for FlowBuilder < 'a > { fn create () -> Self { FlowBuilder :: new () } } # [cfg (stageleft_macro)] impl < 'a > FlowBuilder < 'a > { # [allow (clippy :: new_without_default)] pub fn new () -> FlowBuilder < 'a > { FlowBuilder { ir_leaves : Rc :: new (RefCell :: new (Some (Vec :: new ()))) , nodes : RefCell :: new (vec ! []) , clusters : RefCell :: new (vec ! []) , cycle_ids : RefCell :: new (HashMap :: new ()) , next_node_id : RefCell :: new (0) , finalized : false , _phantom : PhantomData , } } pub fn finalize (mut self) -> built :: BuiltFlow < 'a > { self . finalized = true ; built :: BuiltFlow { ir : self . ir_leaves . borrow_mut () . take () . unwrap () , processes : self . nodes . replace (vec ! []) , clusters : self . clusters . replace (vec ! []) , used : false , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> built :: BuiltFlow < 'a > { self . finalize () . with_default_optimize () } pub fn optimize_with (self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> built :: BuiltFlow < 'a > { self . finalize () . optimize_with (f) } pub fn ir_leaves (& self) -> & FlowLeaves < 'a > { & self . ir_leaves } pub fn process < P > (& self) -> Process < P > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . nodes . borrow_mut () . push (id) ; Process { id , _phantom : PhantomData , } } pub fn cluster < C > (& self) -> Cluster < C > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . clusters . borrow_mut () . push (id) ; Cluster { id , _phantom : PhantomData , } } pub fn runtime_context (& self) -> RuntimeContext < 'a > { RuntimeContext { _phantom : PhantomData , } } pub fn cluster_members < C > (& self , cluster : & Cluster < C > ,) -> impl Quoted < 'a , & 'a Vec < u32 > > + Copy + 'a { ClusterIds { id : cluster . id , _phantom : PhantomData , } } pub fn cluster_self_id < C > (& self , cluster : & Cluster < C >) -> impl Quoted < 'a , u32 > + Copy + 'a { ClusterSelfId { id : cluster . id , _phantom : PhantomData , } } pub fn spin < L : Location > (& self , on : & L) -> Stream < 'a , () , Unbounded , NoTick , L > { Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Spin () , location_kind : on . id () , })) ,) } pub fn spin_batch < L : Location > (& self , on : & L , batch_size : impl Quoted < 'a , usize > + Copy + 'a ,) -> Stream < 'a , () , Bounded , Tick , L > { self . spin (on) . flat_map (q ! (move | _ | 0 .. batch_size)) . map (q ! (| _ | ())) . tick_batch () } pub fn source_stream < T , E : FuturesStream < Item = T > + Unpin , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Unbounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Stream (e . into ()) , location_kind : on . id () , })) ,) } pub fn source_iter < T , E : IntoIterator < Item = T > , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Bounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , })) ,) } pub fn singleton < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Singleton < 'a , T , Bounded , NoTick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Singleton :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,)))) ,) } pub fn singleton_first_tick < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Optional < 'a , T , Bounded , Tick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,) } pub fn source_interval < L : Location > (& self , on : & L , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , () , Unbounded , NoTick , L > { let interval = interval . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : on . id () , })) ,) } pub fn source_interval_delayed < L : Location > (& self , on : & L , delay : impl Quoted < 'a , Duration > + Copy + 'a , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , tokio :: time :: Instant , Unbounded , NoTick , L > { self . source_stream (on , q ! (tokio_stream :: wrappers :: IntervalStream :: new (tokio :: time :: interval_at (tokio :: time :: Instant :: now () + delay , interval))) ,) . tick_batch () . first () . latest () } pub fn cycle < S : CycleCollection < 'a > > (& self , on : & S :: Location) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , on . id ()) ,) } pub fn cycle_with_initial < S : CycleCollectionWithInitial < 'a > > (& self , on : & S :: Location , initial : S ,) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , initial , on . id ()) ,) } } } pub use builder :: FlowBuilder ; pub mod ir { pub use core :: panic ; pub use std :: cell :: RefCell ; pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow_lang :: graph :: FlatGraphBuilder ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: ToTokens ; pub use syn :: parse_quote ; pub use crate :: deploy :: Deploy ; pub use crate :: location :: LocationId ; pub use crate :: ir :: DebugExpr ; # [cfg (stageleft_macro)] impl From < syn :: Expr > for DebugExpr { fn from (expr : syn :: Expr) -> DebugExpr { DebugExpr (expr) } } # [cfg (stageleft_macro)] impl Deref for DebugExpr { type Target = syn :: Expr ; fn deref (& self) -> & Self :: Target { & self . 0 } } # [cfg (stageleft_macro)] impl ToTokens for DebugExpr { fn to_tokens (& self , tokens : & mut TokenStream) { self . 0 . to_tokens (tokens) ; } } # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugExpr { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "{}" , self . 0 . to_token_stream ()) } } pub use crate :: ir :: DebugInstantiate ; # [cfg (stageleft_macro)] impl < 'a > std :: fmt :: Debug for DebugInstantiate < 'a > { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<network instantiate>") } } pub use crate :: ir :: DebugPipelineFn ; # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugPipelineFn { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<function>") } } pub use crate :: ir :: HfPlusSource ; pub use crate :: ir :: HfPlusLeaf ; # [cfg (stageleft_macro)] impl < 'a > HfPlusLeaf < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . compile_network :: < D > (compile_env , s , nodes , clusters) ; } , seen_tees ,) } pub fn connect_network (self , seen_tees : & mut SeenTees < 'a >) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . connect_network (s) ; } , seen_tees ,) } pub fn transform_children (self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) -> HfPlusLeaf < 'a > { match self { HfPlusLeaf :: ForEach { f , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: ForEach { f , input } } HfPlusLeaf :: DestSink { sink , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: DestSink { sink , input } } HfPlusLeaf :: CycleSink { ident , location_kind , mut input , } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: CycleSink { ident , location_kind , input , } } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) { match self { HfPlusLeaf :: ForEach { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> for_each (# f) ; }) ; } HfPlusLeaf :: DestSink { sink , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink) ; }) ; } HfPlusLeaf :: CycleSink { ident , location_kind , input , } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; assert_eq ! (input_location_id , * location_id , "cycle_sink location mismatch") ; graph_builders . entry (* location_id) . or_default () . add_statement (parse_quote ! { # ident = # input_ident ; }) ; } } } } pub use crate :: ir :: HfPlusNode ; pub type SeenTees < 'a > = HashMap < * const RefCell < HfPlusNode < 'a > > , Rc < RefCell < HfPlusNode < 'a > > > > ; # [cfg (stageleft_macro)] impl < 'a > HfPlusNode < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (& mut self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) { self . transform_children (| n , s | n . compile_network :: < D > (compile_env , s , nodes , clusters) , seen_tees ,) ; if let HfPlusNode :: Network { from_location , to_location , instantiate_fn , .. } = self { let (sink_expr , source_expr , connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { let ((sink , source) , connect_fn) = match (from_location , to_location) { (LocationId :: Process (from) , LocationId :: Process (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: o2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Process (from) , LocationId :: Cluster (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: o2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Process (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: m2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Cluster (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: m2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } } ; (sink , source , connect_fn) } DebugInstantiate :: Finalized (_ , _ , _) => panic ! ("network already finalized") , } ; * instantiate_fn = DebugInstantiate :: Finalized (sink_expr , source_expr , connect_fn) ; } } pub fn connect_network (& mut self , seen_tees : & mut SeenTees < 'a >) { self . transform_children (| n , s | n . connect_network (s) , seen_tees) ; if let HfPlusNode :: Network { instantiate_fn , .. } = self { match instantiate_fn { DebugInstantiate :: Building () => panic ! ("network not built") , DebugInstantiate :: Finalized (_ , _ , ref connect_fn) => { connect_fn () ; } } } } pub fn transform_children (& mut self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) { match self { HfPlusNode :: Placeholder => { panic ! () ; } HfPlusNode :: Source { .. } => { } HfPlusNode :: CycleSource { .. } => { } HfPlusNode :: Tee { inner } => { if let Some (transformed) = seen_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { * inner = transformed . clone () ; } else { let transformed_cell = Rc :: new (RefCell :: new (HfPlusNode :: Placeholder)) ; seen_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , transformed_cell . clone () ,) ; let mut orig = inner . replace (HfPlusNode :: Placeholder) ; transform (& mut orig , seen_tees) ; * transformed_cell . borrow_mut () = orig ; * inner = transformed_cell ; } } HfPlusNode :: Persist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Unpersist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Delta (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Union (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossProduct (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossSingleton (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Join (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Difference (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: AntiJoin (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Map { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FlatMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Filter { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FilterMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Sort (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: DeferTick (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Enumerate (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Inspect { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Unique (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Fold { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FoldKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Reduce { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: ReduceKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Network { input , .. } => { transform (input . as_mut () , seen_tees) ; } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) -> (syn :: Ident , usize) { match self { HfPlusNode :: Placeholder => { panic ! () } HfPlusNode :: Persist (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let persist_id = * next_stmt_id ; * next_stmt_id += 1 ; let persist_ident = syn :: Ident :: new (& format ! ("stream_{}" , persist_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # persist_ident = # inner_ident -> persist ::<'static > () ; }) ; (persist_ident , location) } HfPlusNode :: Unpersist (_) => { panic ! ("Unpersist is a marker node and should have been optimized away. This is likely a compiler bug.") } HfPlusNode :: Delta (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let delta_id = * next_stmt_id ; * next_stmt_id += 1 ; let delta_ident = syn :: Ident :: new (& format ! ("stream_{}" , delta_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # delta_ident = # inner_ident -> multiset_delta () ; }) ; (delta_ident , location) } HfPlusNode :: Source { source , location_kind , } => { let source_id = * next_stmt_id ; * next_stmt_id += 1 ; let source_ident = syn :: Ident :: new (& format ! ("stream_{}" , source_id) , Span :: call_site ()) ; let source_stmt = match source { HfPlusSource :: Stream (expr) => { parse_quote ! { # source_ident = source_stream (# expr) ; } } HfPlusSource :: Iter (expr) => { parse_quote ! { # source_ident = source_iter (# expr) ; } } HfPlusSource :: Interval (expr) => { parse_quote ! { # source_ident = source_interval (# expr) ; } } HfPlusSource :: Spin () => { parse_quote ! { # source_ident = spin () ; } } } ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; graph_builders . entry (* location_id) . or_default () . add_statement (source_stmt) ; (source_ident , * location_id) } HfPlusNode :: CycleSource { ident , location_kind , } => { let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; (ident . clone () , * location_id) } HfPlusNode :: Tee { inner } => { if let Some (ret) = built_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { ret . clone () } else { let (inner_ident , inner_location_id) = inner . borrow () . emit (graph_builders , built_tees , next_stmt_id) ; let tee_id = * next_stmt_id ; * next_stmt_id += 1 ; let tee_ident = syn :: Ident :: new (& format ! ("stream_{}" , tee_id) , Span :: call_site ()) ; let builder = graph_builders . entry (inner_location_id) . or_default () ; builder . add_statement (parse_quote ! { # tee_ident = # inner_ident -> tee () ; }) ; built_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , (tee_ident . clone () , inner_location_id) ,) ; (tee_ident , inner_location_id) } } HfPlusNode :: Union (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "union inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let union_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # union_ident = union () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [0] # union_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # union_ident ; }) ; (union_ident , left_location_id) } HfPlusNode :: CrossSingleton (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "cross_singleton inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let cross_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # cross_ident = cross_singleton () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [input] # cross_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [single] # cross_ident ; }) ; (cross_ident , left_location_id) } HfPlusNode :: CrossProduct (..) | HfPlusNode :: Join (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: CrossProduct (..)) { parse_quote ! (cross_join_multiset) } else { parse_quote ! (join_multiset) } ; let (HfPlusNode :: CrossProduct (left , right) | HfPlusNode :: Join (left , right)) = self else { unreachable ! () } ; let (left_inner , left_was_persist) = if let HfPlusNode :: Persist (left) = left . as_ref () { (left , true) } else { (left , false) } ; let (right_inner , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left_inner . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right_inner . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "join / cross product inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; match (left_was_persist , right_was_persist) { (true , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'static > () ; }) ; } (true , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'tick > () ; }) ; } (false , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } (false , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } } ; builder . add_statement (parse_quote ! { # left_ident -> [0] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Difference (..) | HfPlusNode :: AntiJoin (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Difference (..)) { parse_quote ! (difference_multiset) } else { parse_quote ! (anti_join_multiset) } ; let (HfPlusNode :: Difference (left , right) | HfPlusNode :: AntiJoin (left , right)) = self else { unreachable ! () } ; let (right , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "difference / anti join inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; if right_was_persist { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } else { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } builder . add_statement (parse_quote ! { # left_ident -> [pos] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [neg] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Map { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let map_id = * next_stmt_id ; * next_stmt_id += 1 ; let map_ident = syn :: Ident :: new (& format ! ("stream_{}" , map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # map_ident = # input_ident -> map (# f) ; }) ; (map_ident , input_location_id) } HfPlusNode :: FlatMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let flat_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let flat_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , flat_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # flat_map_ident = # input_ident -> flat_map (# f) ; }) ; (flat_map_ident , input_location_id) } HfPlusNode :: Filter { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_ident = # input_ident -> filter (# f) ; }) ; (filter_ident , input_location_id) } HfPlusNode :: FilterMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_map_ident = # input_ident -> filter_map (# f) ; }) ; (filter_map_ident , input_location_id) } HfPlusNode :: Sort (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sort_id = * next_stmt_id ; * next_stmt_id += 1 ; let sort_ident = syn :: Ident :: new (& format ! ("stream_{}" , sort_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # sort_ident = # input_ident -> sort () ; }) ; (sort_ident , input_location_id) } HfPlusNode :: DeferTick (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let defer_tick_id = * next_stmt_id ; * next_stmt_id += 1 ; let defer_tick_ident = syn :: Ident :: new (& format ! ("stream_{}" , defer_tick_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # defer_tick_ident = # input_ident -> defer_tick_lazy () ; }) ; (defer_tick_ident , input_location_id) } HfPlusNode :: Enumerate (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let enumerate_id = * next_stmt_id ; * next_stmt_id += 1 ; let enumerate_ident = syn :: Ident :: new (& format ! ("stream_{}" , enumerate_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # enumerate_ident = # input_ident -> enumerate () ; }) ; (enumerate_ident , input_location_id) } HfPlusNode :: Inspect { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let inspect_id = * next_stmt_id ; * next_stmt_id += 1 ; let inspect_ident = syn :: Ident :: new (& format ! ("stream_{}" , inspect_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # inspect_ident = # input_ident -> inspect (# f) ; }) ; (inspect_ident , input_location_id) } HfPlusNode :: Unique (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let unique_id = * next_stmt_id ; * next_stmt_id += 1 ; let unique_ident = syn :: Ident :: new (& format ! ("stream_{}" , unique_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # unique_ident = # input_ident -> unique ::<'tick > () ; }) ; (unique_ident , input_location_id) } HfPlusNode :: Fold { .. } | HfPlusNode :: FoldKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Fold { .. }) { parse_quote ! (fold) } else { parse_quote ! (fold_keyed) } ; let (HfPlusNode :: Fold { init , acc , input } | HfPlusNode :: FoldKeyed { init , acc , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let fold_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'static > (# init , # acc) ; }) ; } else { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'tick > (# init , # acc) ; }) ; } (fold_ident , input_location_id) } HfPlusNode :: Reduce { .. } | HfPlusNode :: ReduceKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Reduce { .. }) { parse_quote ! (reduce) } else { parse_quote ! (reduce_keyed) } ; let (HfPlusNode :: Reduce { f , input } | HfPlusNode :: ReduceKeyed { f , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let reduce_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'static > (# f) ; }) ; } else { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'tick > (# f) ; }) ; } (reduce_ident , input_location_id) } HfPlusNode :: Network { from_location : _ , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input , } => { let (sink_expr , source_expr , _connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { panic ! ("Expected the network to be finalized") } DebugInstantiate :: Finalized (sink , source , connect_fn) => { (sink , source , connect_fn) } } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sender_builder = graph_builders . entry (input_location_id) . or_default () ; if let Some (serialize_pipeline) = serialize_pipeline { sender_builder . add_statement (parse_quote ! { # input_ident -> # serialize_pipeline -> dest_sink (# sink_expr) ; }) ; } else { sender_builder . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink_expr) ; }) ; } let to_id = match to_location { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let receiver_builder = graph_builders . entry (* to_id) . or_default () ; let receiver_stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let receiver_stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , receiver_stream_id) , Span :: call_site ()) ; if let Some (deserialize_pipeline) = deserialize_pipeline { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) -> # deserialize_pipeline ; }) ; } else { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) ; }) ; } (receiver_stream_ident , * to_id) } } } } } pub mod persist_pullup { pub use std :: cell :: RefCell ; pub use std :: collections :: HashSet ; pub use std :: ops :: Deref ; pub use crate :: ir :: * ; pub fn persist_pullup_node < 'a > (node : & mut HfPlusNode < 'a > , seen_tees : & mut SeenTees < 'a > , persist_pulled_tees : & mut HashSet < * const RefCell < HfPlusNode < 'a > > > ,) { node . transform_children (| n , s | persist_pullup_node (n , s , persist_pulled_tees) , seen_tees ,) ; match node { HfPlusNode :: Unpersist (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Unpersist (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Delta (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Delta (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Tee { inner } => { if persist_pulled_tees . contains (& (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >)) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } else { let inner_borrow = inner . borrow () ; if let HfPlusNode :: Persist (_) = inner_borrow . deref () { drop (inner_borrow) ; persist_pulled_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >) ; if let HfPlusNode :: Persist (box behind_persist) = inner . replace (HfPlusNode :: Placeholder) { * inner . borrow_mut () = behind_persist ; } else { unreachable ! () } * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } } } HfPlusNode :: Map { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Map { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Map { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: FlatMap { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: FlatMap { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: FlatMap { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Filter { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Filter { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Filter { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Network { input : box HfPlusNode :: Persist (_) , .. } => { if let HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Union (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Union (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Union (left , right))) ; } else { unreachable ! () } } HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: CrossProduct (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,) ,)))) ; } else { unreachable ! () } } HfPlusNode :: Join (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Join (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: Join (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,))))) ; } else { unreachable ! () } } _ => { } } } pub fn persist_pullup (ir : Vec < HfPlusLeaf >) -> Vec < HfPlusLeaf > { let mut seen_tees = Default :: default () ; let mut persist_pulled_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| n , s | persist_pullup_node (n , s , & mut persist_pulled_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn persist_pullup_through_map () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } # [test] fn persist_pullup_behind_tee () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; let before_tee = flow . source_iter (& process , q ! (0 .. 10)) . tick_batch () . persist () ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } } } pub mod profiler { pub use std :: cell :: RefCell ; pub use hydroflow :: futures :: channel :: mpsc :: UnboundedSender ; pub use stageleft :: * ; pub use crate as hydroflow_plus ; pub use crate :: ir :: * ; pub use crate :: RuntimeContext ; pub fn increment_counter (count : & mut u64) { * count += 1 ; } pub fn quoted_any_fn < 'a , F : Fn (& usize) + 'a , Q : IntoQuotedMut < 'a , F > > (q : Q) -> Q { q } # [doc = " Add a profiling node before each node to count the cardinality of its input"] pub fn add_profiling_node < 'a > (node : & mut HfPlusNode < 'a > , _context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > , id : & mut u32 , seen_tees : & mut SeenTees < 'a > ,) { let my_id = * id ; * id += 1 ; node . transform_children (| node , seen_tees | { add_profiling_node (node , _context , counters , counter_queue , id , seen_tees) } , seen_tees ,) ; let orig_node = std :: mem :: replace (node , HfPlusNode :: Placeholder) ; * node = HfPlusNode :: Inspect { f : quoted_any_fn (q ! ({ counter_queue . borrow () . unbounded_send ((my_id as usize , counters . borrow () [my_id as usize])) . unwrap () ; counters . borrow_mut () [my_id as usize] = 0 ; move | _ | { hydroflow_plus :: profiler :: increment_counter (& mut counters . borrow_mut () [my_id as usize] ,) ; } })) . splice () . into () , input : Box :: new (orig_node) , } } # [doc = " Count the cardinality of each input and periodically output to a file"] pub fn profiling < 'a > (ir : Vec < HfPlusLeaf < 'a > > , context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > ,) -> Vec < HfPlusLeaf < 'a > > { let mut id = 0 ; let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | { add_profiling_node (node , context , counters , counter_queue , & mut id , seen_tees) } , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn profiler_wrapping_all_operators () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let runtime_context = flow . runtime_context () ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (& built . ir ()) ; let counters = RuntimeData :: new ("Fake") ; let counter_queue = RuntimeData :: new ("Fake") ; let pushed_down = built . with_default_optimize () . optimize_with (| ir | super :: profiling (ir , runtime_context , counters , counter_queue)) ; insta :: assert_debug_snapshot ! (& pushed_down . ir ()) ; let _ = pushed_down . compile_no_network :: < MultiGraph > () ; } } } pub mod properties { pub use std :: collections :: HashSet ; pub use stageleft :: * ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , SeenTees } ; pub use crate :: properties :: PropertyDatabase ; # [doc = " Allows us to convert the hydroflow datatype for folds to a binary operation for the algebra"] # [doc = " property tests."] # [allow (dead_code)] pub fn convert_hf_to_binary < I , A : Default , F : Fn (& mut A , I) > (f : F) -> impl Fn (I , I) -> A { move | a , b | { let mut acc = Default :: default () ; f (& mut acc , a) ; f (& mut acc , b) ; acc } } # [cfg (stageleft_macro)] impl PropertyDatabase { # [doc = " Tags the expression as commutative."] pub fn add_commutative_tag < 'a , I , A , F : Fn (& mut A , I) , Q : Quoted < 'a , F > + Clone > (& mut self , expr : Q ,) -> Q { let expr_clone = expr . clone () ; self . commutative . insert (expr_clone . splice ()) ; expr } pub fn is_tagged_commutative (& self , expr : & syn :: Expr) -> bool { self . commutative . contains (expr) } } pub fn properties_optimize_node < 'a > (node : & mut HfPlusNode < 'a > , db : & PropertyDatabase , seen_tees : & mut SeenTees < 'a > ,) { node . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , seen_tees ,) ; match node { HfPlusNode :: ReduceKeyed { f , .. } if db . is_tagged_commutative (& f . 0) => { dbg ! ("IDENTIFIED COMMUTATIVE OPTIMIZATION for {:?}" , & f) ; } _ => { } } } pub fn properties_optimize < 'a > (ir : Vec < HfPlusLeaf < 'a > > , db : & PropertyDatabase ,) -> Vec < HfPlusLeaf < 'a > > { let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use super :: * ; use crate :: deploy :: SingleProcessGraph ; use crate :: FlowBuilder ; # [test] fn test_property_database () { let mut db = PropertyDatabase :: default () ; assert ! (! db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; let _ = db . add_commutative_tag (q ! (| a : & mut i32 , b : i32 | * a += b)) ; assert ! (db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; } # [test] fn test_property_optimized () { let flow = FlowBuilder :: new () ; let mut database = PropertyDatabase :: default () ; let process = flow . process :: < () > () ; let counter_func = q ! (| count : & mut i32 , _ | * count += 1) ; let _ = database . add_commutative_tag (counter_func) ; flow . source_iter (& process , q ! (vec ! [])) . map (q ! (| string : String | (string , ()))) . tick_batch () . fold_keyed (q ! (|| 0) , counter_func) . all_ticks () . for_each (q ! (| (string , count) | println ! ("{}: {}" , string , count))) ; let built = flow . finalize () . optimize_with (| ir | properties_optimize (ir , & database)) . with_default_optimize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let _ = built . compile_no_network :: < SingleProcessGraph > () ; } } } pub use crate :: RuntimeContext ; # [cfg (stageleft_macro)] impl Copy for RuntimeContext < '_ > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Context > for RuntimeContext < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (quote ! (& context))) } } pub use crate :: HfCompiled ; # [cfg (stageleft_macro)] impl < 'a , ID > HfCompiled < 'a , ID > { pub fn hydroflow_ir (& self) -> & BTreeMap < usize , HydroflowGraph > { & self . hydroflow_ir } } # [cfg (stageleft_macro)] impl < 'a > HfCompiled < 'a , usize > { pub fn with_dynamic_id (self , id : impl Quoted < 'a , usize >) -> HfBuiltWithId < 'a > { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; let mut conditioned_tokens = None ; for (subgraph_id , flat_graph) in self . hydroflow_ir { let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; let my_extra_stmts = self . extra_stmts . get (& subgraph_id) . cloned () . unwrap_or_default () ; if let Some (conditioned_tokens) = conditioned_tokens . as_mut () { * conditioned_tokens = syn :: parse_quote ! { # conditioned_tokens else if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } } ; } else { conditioned_tokens = Some (syn :: parse_quote ! { if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } }) ; } } let conditioned_tokens : TokenStream = conditioned_tokens . unwrap () ; let id = id . splice () ; HfBuiltWithId { tokens : syn :: parse_quote ! ({ let __given_id = # id ; # conditioned_tokens else { panic ! ("Invalid node id: {}" , __given_id) ; } }) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfCompiled < 'a , () > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfCompiled < 'a , () > { fn to_tokens (mut self) -> (Option < TokenStream > , Option < TokenStream >) { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; if self . hydroflow_ir . len () != 1 { panic ! ("Expected exactly one subgraph in the Hydroflow IR") ; } let flat_graph = self . hydroflow_ir . remove (& 0) . unwrap () ; let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; (None , Some (tokens)) } } pub use crate :: HfBuiltWithId ; # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfBuiltWithId < 'a > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfBuiltWithId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (self . tokens)) } }
[INFO] [stdout] 1 + pub use std :: collections :: BTreeMap ; pub use std :: marker :: PhantomData ; pub use hydroflow :: scheduled :: context :: Context ; pub use hydroflow :: scheduled :: graph :: Hydroflow ; pub use hydroflow :: * ; pub use lang :: graph :: { partition_graph , HydroflowGraph } ; pub use proc_macro2 :: TokenStream ; pub use quote :: quote ; pub use stageleft :: runtime_support :: FreeVariable ; pub use stageleft :: Quoted ; pub mod runtime_support { pub use bincode ; } pub mod stream { pub use std :: cell :: RefCell ; pub use std :: hash :: Hash ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow :: bytes :: Bytes ; pub use hydroflow :: futures :: Sink ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: quote ; pub use serde :: de :: DeserializeOwned ; pub use serde :: Serialize ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use syn :: parse_quote ; pub use crate :: builder :: { ClusterIds , FlowLeaves } ; pub use crate :: cycle :: { CycleCollection , CycleComplete } ; pub use crate :: ir :: { DebugInstantiate , HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { CanSend , Location , LocationId } ; pub use crate :: { Cluster , Optional , Singleton } ; pub use crate :: stream :: Unbounded ; pub use crate :: stream :: Bounded ; pub use crate :: stream :: NoTick ; pub use crate :: stream :: Tick ; pub use crate :: stream :: Stream ; # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Stream { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Stream < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Stream { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , C , N > > ,) -> Stream < 'a , (T , O) , W , C , N > where O : Clone , { let other : Optional < 'a , O , Bounded , C , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn cross_product < O > (self , other : Stream < 'a , O , W , C , N >) -> Stream < 'a , (T , O) , W , C , N > where T : Clone , O : Clone , { if self . location_kind != other . location_kind { panic ! ("cross_product must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossProduct (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn union (self , other : Stream < 'a , T , W , C , N >) -> Stream < 'a , T , W , C , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn dest_sink < S : Unpin + Sink < T > + 'a > (self , sink : impl Quoted < 'a , S >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: DestSink { sink : sink . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn first (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } # [doc = " Allow this stream through if the other stream has elements, otherwise the output is empty."] pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } # [doc = " Allow this stream through if the other stream is empty, otherwise the output is empty."] pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn enumerate (self) -> Stream < 'a , (usize , T) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Enumerate (Box :: new (self . ir_node . into_inner ())) ,) } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn sort (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Ord , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Sort (Box :: new (self . ir_node . into_inner ())) ,) } pub fn count (self) -> Singleton < 'a , usize , Bounded , Tick , N > { self . fold (q ! (|| 0usize) , q ! (| count , _ | * count += 1)) } pub fn delta (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } pub fn unique (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Eq + Hash , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unique (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn tick_batch (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_prefix (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { self . tick_batch () . persist () } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn for_each < F : Fn (T) + 'a > (self , f : impl IntoQuotedMut < 'a , F >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: ForEach { input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , f : f . splice () . into () , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Unbounded , NoTick , N > { pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . tick_batch () . continue_if (samples . first ()) . all_ticks () } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Unbounded , NoTick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , C , N : Location > Stream < 'a , T , Bounded , C , N > { pub fn filter_not_in (self , other : Stream < 'a , T , Bounded , C , N >) -> Stream < 'a , T , Bounded , C , N > where T : Eq + Hash , { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Difference (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Stream < 'a , & T , W , C , N > { pub fn cloned (self) -> Stream < 'a , T , W , C , N > { self . map (q ! (| d | d . clone ())) } } # [cfg (stageleft_macro)] impl < 'a , K , V1 , W , C , N : Location > Stream < 'a , (K , V1) , W , C , N > { pub fn join < W2 , V2 > (self , n : Stream < 'a , (K , V2) , W2 , C , N > ,) -> Stream < 'a , (K , (V1 , V2)) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Join (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } pub fn anti_join < W2 > (self , n : Stream < 'a , K , W2 , C , N >) -> Stream < 'a , (K , V1) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("anti_join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: AntiJoin (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , K : Eq + Hash , V , N : Location > Stream < 'a , (K , V) , Bounded , Tick , N > { pub fn fold_keyed < A , I : Fn () -> A + 'a , F : Fn (& mut A , V) + 'a > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , A) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FoldKeyed { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce_keyed < F : Fn (& mut V , V) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , V) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: ReduceKeyed { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } pub fn get_this_crate () -> TokenStream { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , Span :: call_site ()) ; quote ! { # ident } } } } pub fn serialize_bincode < T : Serialize > (is_demux : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if is_demux { parse_quote ! { map (| (id , data) | { (id , # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into ()) }) } } else { parse_quote ! { map (| data | { # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into () }) } } } pub fn deserialize_bincode < T : DeserializeOwned > (tagged : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if tagged { parse_quote ! { map (| res | { let (id , b) = res . unwrap () ; (id , # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& b) . unwrap ()) }) } } else { parse_quote ! { map (| res | { # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& res . unwrap ()) . unwrap () }) } } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn send_bincode < N2 : Location , CoreType > (self , other : & N2 ,) -> Stream < 'a , N :: Out < CoreType > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T > , CoreType : Serialize + DeserializeOwned , { let serialize_pipeline = Some (serialize_bincode :: < CoreType > (N :: is_demux ())) ; let deserialize_pipeline = Some (deserialize_bincode :: < CoreType > (N :: is_tagged ())) ; Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bytes < N2 : Location > (self , other : & N2 ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T > , { Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline : None , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline : if N :: is_tagged () { Some (parse_quote ! (map (| (id , b) | (id , b . unwrap () . freeze ())))) } else { Some (parse_quote ! (map (| b | b . unwrap () . freeze ()))) } , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bincode_interleaved < N2 : Location , Tag , CoreType > (self , other : & N2 ,) -> Stream < 'a , CoreType , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T , Out < CoreType > = (Tag , CoreType) > , CoreType : Serialize + DeserializeOwned , { self . send_bincode :: < N2 , CoreType > (other) . map (q ! (| (_ , b) | b)) } pub fn send_bytes_interleaved < N2 : Location , Tag > (self , other : & N2 ,) -> Stream < 'a , Bytes , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T , Out < Bytes > = (Tag , Bytes) > , { self . send_bytes :: < N2 > (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bincode < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < T > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) > , T : Clone + Serialize + DeserializeOwned , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bincode (other) } pub fn broadcast_bincode_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , T , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) , Out < T > = (Tag , T) > + 'a , T : Clone + Serialize + DeserializeOwned , { self . broadcast_bincode (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bytes < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) > + 'a , T : Clone , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bytes (other) } pub fn broadcast_bytes_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , Bytes , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) , Out < Bytes > = (Tag , Bytes) > + 'a , T : Clone , { self . broadcast_bytes (other) . map (q ! (| (_ , b) | b)) } } } pub use stream :: { Bounded , NoTick , Stream , Tick , Unbounded } ; pub mod singleton { pub use std :: cell :: RefCell ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use crate :: builder :: FlowLeaves ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial , CycleComplete } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: Stream ; pub use crate :: singleton :: CrossResult ; # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Singleton < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Singleton :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } pub use crate :: singleton :: Singleton ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Singleton { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleComplete < 'a > for Singleton < 'a , T , Bounded , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleCollectionWithInitial < 'a > for Singleton < 'a , T , Bounded , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , initial : Self , l : LocationId ,) -> Self { Singleton :: new (l , ir_leaves , HfPlusNode :: Union (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , }) , initial . ir_node . into_inner () . into () ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Singleton < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Singleton { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , U , W , C , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (Self :: other_ir_node (other)) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Singleton < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CrossSingleton (Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , Box :: new (HfPlusNode :: Unpersist (Box :: new (Self :: other_ir_node (other)))) ,))) ,) } } pub use crate :: singleton :: Optional ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Optional { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } pub fn some (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: new (singleton . location_kind , singleton . ir_leaves , singleton . ir_node . into_inner () ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > From < Singleton < 'a , T , W , C , N > > for Optional < 'a , T , W , C , N > { fn from (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: some (singleton) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Optional < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Optional { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn into_stream (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , Tick , N > > ,) -> Optional < 'a , (T , O) , Bounded , Tick , N > where O : Clone , { let other : Optional < 'a , O , Bounded , Tick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn union (self , other : Optional < 'a , T , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Optional < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_samples (self) -> Stream < 'a , T , Unbounded , NoTick , N > { self . latest_tick () . all_ticks () } pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . latest_tick () . continue_if (samples . first ()) . latest () . tick_samples () } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Unbounded , NoTick , N > > ,) -> Optional < 'a , (T , O) , Unbounded , NoTick , N > where O : Clone , { let other : Optional < 'a , O , Unbounded , NoTick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } self . latest_tick () . cross_singleton (other . latest_tick ()) . latest () } } } pub use singleton :: { Optional , Singleton } ; pub mod location { pub use std :: marker :: PhantomData ; pub use crate :: location :: LocationId ; pub use crate :: location :: Location ; pub use crate :: location :: Process ; # [cfg (stageleft_macro)] impl < P > Clone for Process < P > { fn clone (& self) -> Self { Process { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < P > Location for Process < P > { fn id (& self) -> LocationId { LocationId :: Process (self . id) } } pub use crate :: location :: Cluster ; # [cfg (stageleft_macro)] impl < C > Clone for Cluster < C > { fn clone (& self) -> Self { Cluster { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < C > Location for Cluster < C > { fn id (& self) -> LocationId { LocationId :: Cluster (self . id) } } pub use crate :: location :: CanSend ; # [cfg (stageleft_macro)] impl < P1 , P2 > CanSend < Process < P2 > > for Process < P1 > { type In < T > = T ; type Out < T > = T ; fn is_demux () -> bool { false } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < P1 , C2 > CanSend < Cluster < C2 > > for Process < P1 > { type In < T > = (u32 , T) ; type Out < T > = T ; fn is_demux () -> bool { true } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < C1 , P2 > CanSend < Process < P2 > > for Cluster < C1 > { type In < T > = T ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { false } fn is_tagged () -> bool { true } } # [cfg (stageleft_macro)] impl < C1 , C2 > CanSend < Cluster < C2 > > for Cluster < C1 > { type In < T > = (u32 , T) ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { true } fn is_tagged () -> bool { true } } } pub use location :: { Cluster , Process } ; pub mod deploy { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use stageleft :: Quoted ; pub mod graphs { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use super :: { LocalDeploy , Node , ProcessSpec } ; pub use crate :: deploy :: graphs :: SingleProcessGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for SingleProcessGraph { type Process = SingleNode ; type Cluster = SingleNode ; type Meta = () ; type GraphId = () ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { SingleNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { SingleNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , SingleProcessGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> SingleNode { SingleNode { } } } pub use crate :: deploy :: graphs :: SingleNode ; # [cfg (stageleft_macro)] impl Node for SingleNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } pub use crate :: deploy :: graphs :: MultiGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for MultiGraph { type Process = MultiNode ; type Cluster = MultiNode ; type Meta = () ; type GraphId = usize ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { MultiNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { MultiNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , MultiGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> MultiNode { MultiNode { } } } pub use crate :: deploy :: graphs :: MultiNode ; # [cfg (stageleft_macro)] impl Node for MultiNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } } pub use graphs :: * ; pub use crate :: deploy :: LocalDeploy ; pub use crate :: deploy :: Deploy ; # [cfg (stageleft_macro)] impl < 'a , T : Deploy < 'a , Process = N , Cluster = C , Meta = M , GraphId = R > , N : Node < Meta = M > , C : Node < Meta = M > , M : Default , R , > LocalDeploy < 'a > for T { type Process = N ; type Cluster = C ; type Meta = M ; type GraphId = R ; fn has_trivial_node () -> bool { < T as Deploy < 'a > > :: has_trivial_node () } fn trivial_process (id : usize) -> Self :: Process { < T as Deploy < 'a > > :: trivial_process (id) } fn trivial_cluster (id : usize) -> Self :: Cluster { < T as Deploy < 'a > > :: trivail_cluster (id) } } pub use crate :: deploy :: ProcessSpec ; pub use crate :: deploy :: ClusterSpec ; pub use crate :: deploy :: Node ; } pub use deploy :: { ClusterSpec , Deploy , ProcessSpec } ; pub mod cycle { pub use std :: marker :: PhantomData ; pub use crate :: builder :: FlowLeaves ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: cycle :: CycleComplete ; pub use crate :: cycle :: CycleCollection ; pub use crate :: cycle :: CycleCollectionWithInitial ; pub use crate :: cycle :: HfCycle ; # [cfg (stageleft_macro)] impl < 'a , S : CycleComplete < 'a > > HfCycle < 'a , S > { pub fn complete (self , stream : S) { let ident = self . ident ; S :: complete (stream , ident) } } } pub use cycle :: HfCycle ; pub mod builder { pub use std :: cell :: RefCell ; pub use std :: collections :: HashMap ; pub use std :: marker :: PhantomData ; pub use std :: rc :: Rc ; pub use std :: time :: Duration ; pub use hydroflow :: futures :: stream :: Stream as FuturesStream ; pub use hydroflow :: { tokio , tokio_stream } ; pub use internal :: TokenStream ; pub use proc_macro2 :: Span ; pub use quote :: quote ; pub use runtime_support :: FreeVariable ; pub use stageleft :: * ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Cluster , Location , LocationId , Process } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: { HfCycle , Optional , RuntimeContext , Singleton , Stream } ; pub mod built { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use hydroflow_lang :: graph :: { eliminate_extra_unions_tees , HydroflowGraph } ; pub use super :: deploy :: { DeployFlow , DeployResult } ; pub use crate :: deploy :: { ClusterSpec , Deploy , LocalDeploy , ProcessSpec } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Cluster , Process } ; pub use crate :: HfCompiled ; pub use crate :: builder :: built :: BuiltFlow ; # [cfg (stageleft_macro)] impl < 'a > Drop for BuiltFlow < 'a > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped BuiltFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn ir (& self) -> & Vec < HfPlusLeaf < 'a > > { & self . ir } pub fn optimize_with (mut self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> BuiltFlow < 'a > { self . used = true ; BuiltFlow { ir : f (std :: mem :: take (& mut self . ir)) , processes : std :: mem :: take (& mut self . processes) , clusters : std :: mem :: take (& mut self . clusters) , used : false , _phantom : PhantomData , } } } pub fn build_inner (ir : & mut Vec < HfPlusLeaf >) -> BTreeMap < usize , HydroflowGraph > { let mut builders = BTreeMap :: new () ; let mut built_tees = HashMap :: new () ; let mut next_stmt_id = 0 ; for leaf in ir { leaf . emit (& mut builders , & mut built_tees , & mut next_stmt_id) ; } builders . into_iter () . map (| (k , v) | { let (mut flat_graph , _ , _) = v . build () ; eliminate_extra_unions_tees (& mut flat_graph) ; (k , flat_graph) }) . collect () } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn compile_no_network < D : LocalDeploy < 'a > > (mut self) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; HfCompiled { hydroflow_ir : build_inner (& mut self . ir) , extra_stmts : BTreeMap :: new () , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> BuiltFlow < 'a > { self . optimize_with (crate :: persist_pullup :: persist_pullup) } fn into_deploy < D : LocalDeploy < 'a > > (mut self) -> DeployFlow < 'a , D > { self . used = true ; let processes = if D :: has_trivial_node () { self . processes . iter () . map (| id | (* id , D :: trivial_process (* id))) . collect () } else { HashMap :: new () } ; let clusters = if D :: has_trivial_node () { self . clusters . iter () . map (| id | (* id , D :: trivial_cluster (* id))) . collect () } else { HashMap :: new () } ; DeployFlow { ir : std :: mem :: take (& mut self . ir) , nodes : processes , clusters , used : false , _phantom : PhantomData , } } pub fn with_process < P , D : LocalDeploy < 'a > > (self , process : & Process < P > , spec : impl ProcessSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_process (process , spec) } pub fn with_cluster < C , D : LocalDeploy < 'a > > (self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_cluster (cluster , spec) } pub fn compile < D : Deploy < 'a > + 'a > (self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . into_deploy :: < D > () . compile (env) } pub fn deploy < D : Deploy < 'a , CompileEnv = () > + 'a > (self , env : & mut D :: InstantiateEnv ,) -> DeployResult < 'a , D > { self . into_deploy :: < D > () . deploy (env) } } } pub mod deploy { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use proc_macro2 :: Span ; pub use stageleft :: Quoted ; pub use super :: built :: build_inner ; pub use crate :: deploy :: { LocalDeploy , Node } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: { Cluster , ClusterSpec , Deploy , HfCompiled , Process , ProcessSpec } ; pub use crate :: builder :: deploy :: DeployFlow ; # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > Drop for DeployFlow < 'a , D > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped DeployFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > DeployFlow < 'a , D > { pub fn with_process < P > (mut self , process : & Process < P > , spec : impl ProcessSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < P > () . to_string () ; self . nodes . insert (process . id , spec . build (process . id , & tag_name)) ; self } pub fn with_cluster < C > (mut self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < C > () . to_string () ; self . clusters . insert (cluster . id , spec . build (cluster . id , & tag_name)) ; self } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployFlow < 'a , D > { pub fn compile (mut self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; let mut seen_tees : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | leaf . compile_network :: < D > (env , & mut seen_tees , & self . nodes , & self . clusters)) . collect () ; let extra_stmts = self . extra_stmts (env) ; HfCompiled { hydroflow_ir : build_inner (& mut ir_leaves_networked) , extra_stmts , _phantom : PhantomData , } } fn extra_stmts (& self , env : & < D as Deploy < 'a > > :: CompileEnv) -> BTreeMap < usize , Vec < syn :: Stmt > > { let all_locations_count = self . nodes . len () + self . clusters . len () ; let mut extra_stmts : BTreeMap < usize , Vec < syn :: Stmt > > = BTreeMap :: new () ; for & c_id in self . clusters . keys () { let self_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , c_id) , Span :: call_site () ,) ; let self_id_expr = D :: cluster_self_id (env) . splice () ; extra_stmts . entry (c_id) . or_default () . push (syn :: parse_quote ! { let # self_id_ident = # self_id_expr ; }) ; for other_location in 0 .. all_locations_count { let other_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , c_id) , Span :: call_site () ,) ; let other_id_expr = D :: cluster_ids (env , c_id) . splice () ; extra_stmts . entry (other_location) . or_default () . push (syn :: parse_quote ! { let # other_id_ident = # other_id_expr ; }) ; } } extra_stmts } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a , CompileEnv = () > > DeployFlow < 'a , D > { # [must_use] pub fn deploy (mut self , env : & mut D :: InstantiateEnv) -> DeployResult < 'a , D > { self . used = true ; let mut seen_tees_instantiate : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | { leaf . compile_network :: < D > (& () , & mut seen_tees_instantiate , & self . nodes , & self . clusters ,) }) . collect () ; let mut compiled = build_inner (& mut ir_leaves_networked) ; let mut extra_stmts = self . extra_stmts (& ()) ; let mut meta = D :: Meta :: default () ; let (mut processes , mut clusters) = (std :: mem :: take (& mut self . nodes) . into_iter () . map (| (node_id , node) | { node . instantiate (env , & mut meta , compiled . remove (& node_id) . unwrap () , extra_stmts . remove (& node_id) . unwrap_or_default () ,) ; (node_id , node) }) . collect :: < HashMap < _ , _ > > () , std :: mem :: take (& mut self . clusters) . into_iter () . map (| (cluster_id , cluster) | { cluster . instantiate (env , & mut meta , compiled . remove (& cluster_id) . unwrap () , extra_stmts . remove (& cluster_id) . unwrap_or_default () ,) ; (cluster_id , cluster) }) . collect :: < HashMap < _ , _ > > () ,) ; for node in processes . values_mut () { node . update_meta (& meta) ; } for cluster in clusters . values_mut () { cluster . update_meta (& meta) ; } let mut seen_tees_connect = HashMap :: new () ; for leaf in ir_leaves_networked { leaf . connect_network (& mut seen_tees_connect) ; } DeployResult { processes , clusters , } } } pub use crate :: builder :: deploy :: DeployResult ; # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployResult < 'a , D > { pub fn get_process < P > (& self , p : & Process < P >) -> & D :: Process { let id = match p . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . processes . get (& id) . unwrap () } pub fn get_cluster < C > (& self , c : & Cluster < C >) -> & D :: Cluster { let id = match c . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . clusters . get (& id) . unwrap () } } } # [doc = " Tracks the leaves of the dataflow IR. This is referenced by"] # [doc = " `Stream` and `HfCycle` to build the IR. The inner option will"] # [doc = " be set to `None` when this builder is finalized."] pub type FlowLeaves < 'a > = Rc < RefCell < Option < Vec < HfPlusLeaf < 'a > > > > > ; pub use crate :: builder :: ClusterIds ; # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Vec < u32 > > for ClusterIds < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , & 'a Vec < u32 > > for ClusterIds < 'a > { } # [derive (Copy , Clone)] pub struct ClusterSelfId < 'a > { pub id : usize , pub _phantom : PhantomData < & 'a mut & 'a u32 > , } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < u32 > for ClusterSelfId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , u32 > for ClusterSelfId < 'a > { } pub use crate :: builder :: FlowBuilder ; # [cfg (stageleft_macro)] impl < 'a > Drop for FlowBuilder < 'a > { fn drop (& mut self) { if ! self . finalized { panic ! ("Dropped FlowBuilder without finalizing, you may have forgotten to call `with_default_optimize`, `optimize_with`, or `finalize`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > QuotedContext for FlowBuilder < 'a > { fn create () -> Self { FlowBuilder :: new () } } # [cfg (stageleft_macro)] impl < 'a > FlowBuilder < 'a > { # [allow (clippy :: new_without_default)] pub fn new () -> FlowBuilder < 'a > { FlowBuilder { ir_leaves : Rc :: new (RefCell :: new (Some (Vec :: new ()))) , nodes : RefCell :: new (vec ! []) , clusters : RefCell :: new (vec ! []) , cycle_ids : RefCell :: new (HashMap :: new ()) , next_node_id : RefCell :: new (0) , finalized : false , _phantom : PhantomData , } } pub fn finalize (mut self) -> built :: BuiltFlow < 'a > { self . finalized = true ; built :: BuiltFlow { ir : self . ir_leaves . borrow_mut () . take () . unwrap () , processes : self . nodes . replace (vec ! []) , clusters : self . clusters . replace (vec ! []) , used : false , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> built :: BuiltFlow < 'a > { self . finalize () . with_default_optimize () } pub fn optimize_with (self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> built :: BuiltFlow < 'a > { self . finalize () . optimize_with (f) } pub fn ir_leaves (& self) -> & FlowLeaves < 'a > { & self . ir_leaves } pub fn process < P > (& self) -> Process < P > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . nodes . borrow_mut () . push (id) ; Process { id , _phantom : PhantomData , } } pub fn cluster < C > (& self) -> Cluster < C > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . clusters . borrow_mut () . push (id) ; Cluster { id , _phantom : PhantomData , } } pub fn runtime_context (& self) -> RuntimeContext < 'a > { RuntimeContext { _phantom : PhantomData , } } pub fn cluster_members < C > (& self , cluster : & Cluster < C > ,) -> impl Quoted < 'a , & 'a Vec < u32 > > + Copy + 'a { ClusterIds { id : cluster . id , _phantom : PhantomData , } } pub fn cluster_self_id < C > (& self , cluster : & Cluster < C >) -> impl Quoted < 'a , u32 > + Copy + 'a { ClusterSelfId { id : cluster . id , _phantom : PhantomData , } } pub fn spin < L : Location > (& self , on : & L) -> Stream < 'a , () , Unbounded , NoTick , L > { Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Spin () , location_kind : on . id () , })) ,) } pub fn spin_batch < L : Location > (& self , on : & L , batch_size : impl Quoted < 'a , usize > + Copy + 'a ,) -> Stream < 'a , () , Bounded , Tick , L > { self . spin (on) . flat_map (q ! (move | _ | 0 .. batch_size)) . map (q ! (| _ | ())) . tick_batch () } pub fn source_stream < T , E : FuturesStream < Item = T > + Unpin , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Unbounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Stream (e . into ()) , location_kind : on . id () , })) ,) } pub fn source_iter < T , E : IntoIterator < Item = T > , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Bounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , })) ,) } pub fn singleton < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Singleton < 'a , T , Bounded , NoTick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Singleton :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,)))) ,) } pub fn singleton_first_tick < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Optional < 'a , T , Bounded , Tick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,) } pub fn source_interval < L : Location > (& self , on : & L , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , () , Unbounded , NoTick , L > { let interval = interval . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : on . id () , })) ,) } pub fn source_interval_delayed < L : Location > (& self , on : & L , delay : impl Quoted < 'a , Duration > + Copy + 'a , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , tokio :: time :: Instant , Unbounded , NoTick , L > { self . source_stream (on , q ! (tokio_stream :: wrappers :: IntervalStream :: new (tokio :: time :: interval_at (tokio :: time :: Instant :: now () + delay , interval))) ,) . tick_batch () . first () . latest () } pub fn cycle < S : CycleCollection < 'a > > (& self , on : & S :: Location) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , on . id ()) ,) } pub fn cycle_with_initial < S : CycleCollectionWithInitial < 'a > > (& self , on : & S :: Location , initial : S ,) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , initial , on . id ()) ,) } } } pub use builder :: FlowBuilder ; pub mod ir { pub use core :: panic ; pub use std :: cell :: RefCell ; pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow_lang :: graph :: FlatGraphBuilder ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: ToTokens ; pub use syn :: parse_quote ; pub use crate :: deploy :: Deploy ; pub use crate :: location :: LocationId ; pub use crate :: ir :: DebugExpr ; # [cfg (stageleft_macro)] impl From < syn :: Expr > for DebugExpr { fn from (expr : syn :: Expr) -> DebugExpr { DebugExpr (expr) } } # [cfg (stageleft_macro)] impl Deref for DebugExpr { type Target = syn :: Expr ; fn deref (& self) -> & Self :: Target { & self . 0 } } # [cfg (stageleft_macro)] impl ToTokens for DebugExpr { fn to_tokens (& self , tokens : & mut TokenStream) { self . 0 . to_tokens (tokens) ; } } # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugExpr { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "{}" , self . 0 . to_token_stream ()) } } pub use crate :: ir :: DebugInstantiate ; # [cfg (stageleft_macro)] impl < 'a > std :: fmt :: Debug for DebugInstantiate < 'a > { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<network instantiate>") } } pub use crate :: ir :: DebugPipelineFn ; # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugPipelineFn { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<function>") } } pub use crate :: ir :: HfPlusSource ; pub use crate :: ir :: HfPlusLeaf ; # [cfg (stageleft_macro)] impl < 'a > HfPlusLeaf < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . compile_network :: < D > (compile_env , s , nodes , clusters) ; } , seen_tees ,) } pub fn connect_network (self , seen_tees : & mut SeenTees < 'a >) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . connect_network (s) ; } , seen_tees ,) } pub fn transform_children (self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) -> HfPlusLeaf < 'a > { match self { HfPlusLeaf :: ForEach { f , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: ForEach { f , input } } HfPlusLeaf :: DestSink { sink , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: DestSink { sink , input } } HfPlusLeaf :: CycleSink { ident , location_kind , mut input , } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: CycleSink { ident , location_kind , input , } } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) { match self { HfPlusLeaf :: ForEach { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> for_each (# f) ; }) ; } HfPlusLeaf :: DestSink { sink , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink) ; }) ; } HfPlusLeaf :: CycleSink { ident , location_kind , input , } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; assert_eq ! (input_location_id , * location_id , "cycle_sink location mismatch") ; graph_builders . entry (* location_id) . or_default () . add_statement (parse_quote ! { # ident = # input_ident ; }) ; } } } } pub use crate :: ir :: HfPlusNode ; pub type SeenTees < 'a > = HashMap < * const RefCell < HfPlusNode < 'a > > , Rc < RefCell < HfPlusNode < 'a > > > > ; # [cfg (stageleft_macro)] impl < 'a > HfPlusNode < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (& mut self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) { self . transform_children (| n , s | n . compile_network :: < D > (compile_env , s , nodes , clusters) , seen_tees ,) ; if let HfPlusNode :: Network { from_location , to_location , instantiate_fn , .. } = self { let (sink_expr , source_expr , connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { let ((sink , source) , connect_fn) = match (from_location , to_location) { (LocationId :: Process (from) , LocationId :: Process (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: o2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Process (from) , LocationId :: Cluster (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: o2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Process (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: m2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Cluster (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: m2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } } ; (sink , source , connect_fn) } DebugInstantiate :: Finalized (_ , _ , _) => panic ! ("network already finalized") , } ; * instantiate_fn = DebugInstantiate :: Finalized (sink_expr , source_expr , connect_fn) ; } } pub fn connect_network (& mut self , seen_tees : & mut SeenTees < 'a >) { self . transform_children (| n , s | n . connect_network (s) , seen_tees) ; if let HfPlusNode :: Network { instantiate_fn , .. } = self { match instantiate_fn { DebugInstantiate :: Building () => panic ! ("network not built") , DebugInstantiate :: Finalized (_ , _ , ref connect_fn) => { connect_fn () ; } } } } pub fn transform_children (& mut self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) { match self { HfPlusNode :: Placeholder => { panic ! () ; } HfPlusNode :: Source { .. } => { } HfPlusNode :: CycleSource { .. } => { } HfPlusNode :: Tee { inner } => { if let Some (transformed) = seen_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { * inner = transformed . clone () ; } else { let transformed_cell = Rc :: new (RefCell :: new (HfPlusNode :: Placeholder)) ; seen_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , transformed_cell . clone () ,) ; let mut orig = inner . replace (HfPlusNode :: Placeholder) ; transform (& mut orig , seen_tees) ; * transformed_cell . borrow_mut () = orig ; * inner = transformed_cell ; } } HfPlusNode :: Persist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Unpersist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Delta (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Union (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossProduct (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossSingleton (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Join (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Difference (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: AntiJoin (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Map { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FlatMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Filter { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FilterMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Sort (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: DeferTick (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Enumerate (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Inspect { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Unique (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Fold { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FoldKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Reduce { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: ReduceKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Network { input , .. } => { transform (input . as_mut () , seen_tees) ; } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) -> (syn :: Ident , usize) { match self { HfPlusNode :: Placeholder => { panic ! () } HfPlusNode :: Persist (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let persist_id = * next_stmt_id ; * next_stmt_id += 1 ; let persist_ident = syn :: Ident :: new (& format ! ("stream_{}" , persist_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # persist_ident = # inner_ident -> persist ::<'static > () ; }) ; (persist_ident , location) } HfPlusNode :: Unpersist (_) => { panic ! ("Unpersist is a marker node and should have been optimized away. This is likely a compiler bug.") } HfPlusNode :: Delta (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let delta_id = * next_stmt_id ; * next_stmt_id += 1 ; let delta_ident = syn :: Ident :: new (& format ! ("stream_{}" , delta_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # delta_ident = # inner_ident -> multiset_delta () ; }) ; (delta_ident , location) } HfPlusNode :: Source { source , location_kind , } => { let source_id = * next_stmt_id ; * next_stmt_id += 1 ; let source_ident = syn :: Ident :: new (& format ! ("stream_{}" , source_id) , Span :: call_site ()) ; let source_stmt = match source { HfPlusSource :: Stream (expr) => { parse_quote ! { # source_ident = source_stream (# expr) ; } } HfPlusSource :: Iter (expr) => { parse_quote ! { # source_ident = source_iter (# expr) ; } } HfPlusSource :: Interval (expr) => { parse_quote ! { # source_ident = source_interval (# expr) ; } } HfPlusSource :: Spin () => { parse_quote ! { # source_ident = spin () ; } } } ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; graph_builders . entry (* location_id) . or_default () . add_statement (source_stmt) ; (source_ident , * location_id) } HfPlusNode :: CycleSource { ident , location_kind , } => { let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; (ident . clone () , * location_id) } HfPlusNode :: Tee { inner } => { if let Some (ret) = built_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { ret . clone () } else { let (inner_ident , inner_location_id) = inner . borrow () . emit (graph_builders , built_tees , next_stmt_id) ; let tee_id = * next_stmt_id ; * next_stmt_id += 1 ; let tee_ident = syn :: Ident :: new (& format ! ("stream_{}" , tee_id) , Span :: call_site ()) ; let builder = graph_builders . entry (inner_location_id) . or_default () ; builder . add_statement (parse_quote ! { # tee_ident = # inner_ident -> tee () ; }) ; built_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , (tee_ident . clone () , inner_location_id) ,) ; (tee_ident , inner_location_id) } } HfPlusNode :: Union (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "union inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let union_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # union_ident = union () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [0] # union_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # union_ident ; }) ; (union_ident , left_location_id) } HfPlusNode :: CrossSingleton (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "cross_singleton inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let cross_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # cross_ident = cross_singleton () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [input] # cross_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [single] # cross_ident ; }) ; (cross_ident , left_location_id) } HfPlusNode :: CrossProduct (..) | HfPlusNode :: Join (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: CrossProduct (..)) { parse_quote ! (cross_join_multiset) } else { parse_quote ! (join_multiset) } ; let (HfPlusNode :: CrossProduct (left , right) | HfPlusNode :: Join (left , right)) = self else { unreachable ! () } ; let (left_inner , left_was_persist) = if let HfPlusNode :: Persist (left) = left . as_ref () { (left , true) } else { (left , false) } ; let (right_inner , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left_inner . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right_inner . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "join / cross product inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; match (left_was_persist , right_was_persist) { (true , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'static > () ; }) ; } (true , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'tick > () ; }) ; } (false , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } (false , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } } ; builder . add_statement (parse_quote ! { # left_ident -> [0] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Difference (..) | HfPlusNode :: AntiJoin (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Difference (..)) { parse_quote ! (difference_multiset) } else { parse_quote ! (anti_join_multiset) } ; let (HfPlusNode :: Difference (left , right) | HfPlusNode :: AntiJoin (left , right)) = self else { unreachable ! () } ; let (right , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "difference / anti join inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; if right_was_persist { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } else { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } builder . add_statement (parse_quote ! { # left_ident -> [pos] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [neg] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Map { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let map_id = * next_stmt_id ; * next_stmt_id += 1 ; let map_ident = syn :: Ident :: new (& format ! ("stream_{}" , map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # map_ident = # input_ident -> map (# f) ; }) ; (map_ident , input_location_id) } HfPlusNode :: FlatMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let flat_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let flat_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , flat_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # flat_map_ident = # input_ident -> flat_map (# f) ; }) ; (flat_map_ident , input_location_id) } HfPlusNode :: Filter { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_ident = # input_ident -> filter (# f) ; }) ; (filter_ident , input_location_id) } HfPlusNode :: FilterMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_map_ident = # input_ident -> filter_map (# f) ; }) ; (filter_map_ident , input_location_id) } HfPlusNode :: Sort (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sort_id = * next_stmt_id ; * next_stmt_id += 1 ; let sort_ident = syn :: Ident :: new (& format ! ("stream_{}" , sort_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # sort_ident = # input_ident -> sort () ; }) ; (sort_ident , input_location_id) } HfPlusNode :: DeferTick (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let defer_tick_id = * next_stmt_id ; * next_stmt_id += 1 ; let defer_tick_ident = syn :: Ident :: new (& format ! ("stream_{}" , defer_tick_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # defer_tick_ident = # input_ident -> defer_tick_lazy () ; }) ; (defer_tick_ident , input_location_id) } HfPlusNode :: Enumerate (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let enumerate_id = * next_stmt_id ; * next_stmt_id += 1 ; let enumerate_ident = syn :: Ident :: new (& format ! ("stream_{}" , enumerate_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # enumerate_ident = # input_ident -> enumerate () ; }) ; (enumerate_ident , input_location_id) } HfPlusNode :: Inspect { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let inspect_id = * next_stmt_id ; * next_stmt_id += 1 ; let inspect_ident = syn :: Ident :: new (& format ! ("stream_{}" , inspect_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # inspect_ident = # input_ident -> inspect (# f) ; }) ; (inspect_ident , input_location_id) } HfPlusNode :: Unique (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let unique_id = * next_stmt_id ; * next_stmt_id += 1 ; let unique_ident = syn :: Ident :: new (& format ! ("stream_{}" , unique_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # unique_ident = # input_ident -> unique ::<'tick > () ; }) ; (unique_ident , input_location_id) } HfPlusNode :: Fold { .. } | HfPlusNode :: FoldKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Fold { .. }) { parse_quote ! (fold) } else { parse_quote ! (fold_keyed) } ; let (HfPlusNode :: Fold { init , acc , input } | HfPlusNode :: FoldKeyed { init , acc , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let fold_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'static > (# init , # acc) ; }) ; } else { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'tick > (# init , # acc) ; }) ; } (fold_ident , input_location_id) } HfPlusNode :: Reduce { .. } | HfPlusNode :: ReduceKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Reduce { .. }) { parse_quote ! (reduce) } else { parse_quote ! (reduce_keyed) } ; let (HfPlusNode :: Reduce { f , input } | HfPlusNode :: ReduceKeyed { f , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let reduce_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'static > (# f) ; }) ; } else { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'tick > (# f) ; }) ; } (reduce_ident , input_location_id) } HfPlusNode :: Network { from_location : _ , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input , } => { let (sink_expr , source_expr , _connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { panic ! ("Expected the network to be finalized") } DebugInstantiate :: Finalized (sink , source , connect_fn) => { (sink , source , connect_fn) } } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sender_builder = graph_builders . entry (input_location_id) . or_default () ; if let Some (serialize_pipeline) = serialize_pipeline { sender_builder . add_statement (parse_quote ! { # input_ident -> # serialize_pipeline -> dest_sink (# sink_expr) ; }) ; } else { sender_builder . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink_expr) ; }) ; } let to_id = match to_location { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let receiver_builder = graph_builders . entry (* to_id) . or_default () ; let receiver_stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let receiver_stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , receiver_stream_id) , Span :: call_site ()) ; if let Some (deserialize_pipeline) = deserialize_pipeline { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) -> # deserialize_pipeline ; }) ; } else { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) ; }) ; } (receiver_stream_ident , * to_id) } } } } } pub mod persist_pullup { pub use std :: cell :: RefCell ; pub use std :: collections :: HashSet ; pub use std :: ops :: Deref ; pub use crate :: ir :: * ; pub fn persist_pullup_node < 'a > (node : & mut HfPlusNode < 'a > , seen_tees : & mut SeenTees < 'a > , persist_pulled_tees : & mut HashSet < * const RefCell < HfPlusNode < 'a > > > ,) { node . transform_children (| n , s | persist_pullup_node (n , s , persist_pulled_tees) , seen_tees ,) ; match node { HfPlusNode :: Unpersist (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Unpersist (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Delta (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Delta (deref!(HfPlusNode :: Persist (box behind_persist))) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Tee { inner } => { if persist_pulled_tees . contains (& (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >)) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } else { let inner_borrow = inner . borrow () ; if let HfPlusNode :: Persist (_) = inner_borrow . deref () { drop (inner_borrow) ; persist_pulled_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >) ; if let HfPlusNode :: Persist (box behind_persist) = inner . replace (HfPlusNode :: Placeholder) { * inner . borrow_mut () = behind_persist ; } else { unreachable ! () } * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } } } HfPlusNode :: Map { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Map { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Map { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: FlatMap { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: FlatMap { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: FlatMap { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Filter { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Filter { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Filter { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Network { input : box HfPlusNode :: Persist (_) , .. } => { if let HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Union (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Union (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Union (left , right))) ; } else { unreachable ! () } } HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: CrossProduct (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,) ,)))) ; } else { unreachable ! () } } HfPlusNode :: Join (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Join (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: Join (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,))))) ; } else { unreachable ! () } } _ => { } } } pub fn persist_pullup (ir : Vec < HfPlusLeaf >) -> Vec < HfPlusLeaf > { let mut seen_tees = Default :: default () ; let mut persist_pulled_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| n , s | persist_pullup_node (n , s , & mut persist_pulled_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn persist_pullup_through_map () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } # [test] fn persist_pullup_behind_tee () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; let before_tee = flow . source_iter (& process , q ! (0 .. 10)) . tick_batch () . persist () ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } } } pub mod profiler { pub use std :: cell :: RefCell ; pub use hydroflow :: futures :: channel :: mpsc :: UnboundedSender ; pub use stageleft :: * ; pub use crate as hydroflow_plus ; pub use crate :: ir :: * ; pub use crate :: RuntimeContext ; pub fn increment_counter (count : & mut u64) { * count += 1 ; } pub fn quoted_any_fn < 'a , F : Fn (& usize) + 'a , Q : IntoQuotedMut < 'a , F > > (q : Q) -> Q { q } # [doc = " Add a profiling node before each node to count the cardinality of its input"] pub fn add_profiling_node < 'a > (node : & mut HfPlusNode < 'a > , _context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > , id : & mut u32 , seen_tees : & mut SeenTees < 'a > ,) { let my_id = * id ; * id += 1 ; node . transform_children (| node , seen_tees | { add_profiling_node (node , _context , counters , counter_queue , id , seen_tees) } , seen_tees ,) ; let orig_node = std :: mem :: replace (node , HfPlusNode :: Placeholder) ; * node = HfPlusNode :: Inspect { f : quoted_any_fn (q ! ({ counter_queue . borrow () . unbounded_send ((my_id as usize , counters . borrow () [my_id as usize])) . unwrap () ; counters . borrow_mut () [my_id as usize] = 0 ; move | _ | { hydroflow_plus :: profiler :: increment_counter (& mut counters . borrow_mut () [my_id as usize] ,) ; } })) . splice () . into () , input : Box :: new (orig_node) , } } # [doc = " Count the cardinality of each input and periodically output to a file"] pub fn profiling < 'a > (ir : Vec < HfPlusLeaf < 'a > > , context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > ,) -> Vec < HfPlusLeaf < 'a > > { let mut id = 0 ; let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | { add_profiling_node (node , context , counters , counter_queue , & mut id , seen_tees) } , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn profiler_wrapping_all_operators () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let runtime_context = flow . runtime_context () ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (& built . ir ()) ; let counters = RuntimeData :: new ("Fake") ; let counter_queue = RuntimeData :: new ("Fake") ; let pushed_down = built . with_default_optimize () . optimize_with (| ir | super :: profiling (ir , runtime_context , counters , counter_queue)) ; insta :: assert_debug_snapshot ! (& pushed_down . ir ()) ; let _ = pushed_down . compile_no_network :: < MultiGraph > () ; } } } pub mod properties { pub use std :: collections :: HashSet ; pub use stageleft :: * ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , SeenTees } ; pub use crate :: properties :: PropertyDatabase ; # [doc = " Allows us to convert the hydroflow datatype for folds to a binary operation for the algebra"] # [doc = " property tests."] # [allow (dead_code)] pub fn convert_hf_to_binary < I , A : Default , F : Fn (& mut A , I) > (f : F) -> impl Fn (I , I) -> A { move | a , b | { let mut acc = Default :: default () ; f (& mut acc , a) ; f (& mut acc , b) ; acc } } # [cfg (stageleft_macro)] impl PropertyDatabase { # [doc = " Tags the expression as commutative."] pub fn add_commutative_tag < 'a , I , A , F : Fn (& mut A , I) , Q : Quoted < 'a , F > + Clone > (& mut self , expr : Q ,) -> Q { let expr_clone = expr . clone () ; self . commutative . insert (expr_clone . splice ()) ; expr } pub fn is_tagged_commutative (& self , expr : & syn :: Expr) -> bool { self . commutative . contains (expr) } } pub fn properties_optimize_node < 'a > (node : & mut HfPlusNode < 'a > , db : & PropertyDatabase , seen_tees : & mut SeenTees < 'a > ,) { node . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , seen_tees ,) ; match node { HfPlusNode :: ReduceKeyed { f , .. } if db . is_tagged_commutative (& f . 0) => { dbg ! ("IDENTIFIED COMMUTATIVE OPTIMIZATION for {:?}" , & f) ; } _ => { } } } pub fn properties_optimize < 'a > (ir : Vec < HfPlusLeaf < 'a > > , db : & PropertyDatabase ,) -> Vec < HfPlusLeaf < 'a > > { let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use super :: * ; use crate :: deploy :: SingleProcessGraph ; use crate :: FlowBuilder ; # [test] fn test_property_database () { let mut db = PropertyDatabase :: default () ; assert ! (! db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; let _ = db . add_commutative_tag (q ! (| a : & mut i32 , b : i32 | * a += b)) ; assert ! (db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; } # [test] fn test_property_optimized () { let flow = FlowBuilder :: new () ; let mut database = PropertyDatabase :: default () ; let process = flow . process :: < () > () ; let counter_func = q ! (| count : & mut i32 , _ | * count += 1) ; let _ = database . add_commutative_tag (counter_func) ; flow . source_iter (& process , q ! (vec ! [])) . map (q ! (| string : String | (string , ()))) . tick_batch () . fold_keyed (q ! (|| 0) , counter_func) . all_ticks () . for_each (q ! (| (string , count) | println ! ("{}: {}" , string , count))) ; let built = flow . finalize () . optimize_with (| ir | properties_optimize (ir , & database)) . with_default_optimize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let _ = built . compile_no_network :: < SingleProcessGraph > () ; } } } pub use crate :: RuntimeContext ; # [cfg (stageleft_macro)] impl Copy for RuntimeContext < '_ > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Context > for RuntimeContext < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (quote ! (& context))) } } pub use crate :: HfCompiled ; # [cfg (stageleft_macro)] impl < 'a , ID > HfCompiled < 'a , ID > { pub fn hydroflow_ir (& self) -> & BTreeMap < usize , HydroflowGraph > { & self . hydroflow_ir } } # [cfg (stageleft_macro)] impl < 'a > HfCompiled < 'a , usize > { pub fn with_dynamic_id (self , id : impl Quoted < 'a , usize >) -> HfBuiltWithId < 'a > { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; let mut conditioned_tokens = None ; for (subgraph_id , flat_graph) in self . hydroflow_ir { let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; let my_extra_stmts = self . extra_stmts . get (& subgraph_id) . cloned () . unwrap_or_default () ; if let Some (conditioned_tokens) = conditioned_tokens . as_mut () { * conditioned_tokens = syn :: parse_quote ! { # conditioned_tokens else if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } } ; } else { conditioned_tokens = Some (syn :: parse_quote ! { if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } }) ; } } let conditioned_tokens : TokenStream = conditioned_tokens . unwrap () ; let id = id . splice () ; HfBuiltWithId { tokens : syn :: parse_quote ! ({ let __given_id = # id ; # conditioned_tokens else { panic ! ("Invalid node id: {}" , __given_id) ; } }) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfCompiled < 'a , () > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfCompiled < 'a , () > { fn to_tokens (mut self) -> (Option < TokenStream > , Option < TokenStream >) { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; if self . hydroflow_ir . len () != 1 { panic ! ("Expected exactly one subgraph in the Hydroflow IR") ; } let flat_graph = self . hydroflow_ir . remove (& 0) . unwrap () ; let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; (None , Some (tokens)) } } pub use crate :: HfBuiltWithId ; # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfBuiltWithId < 'a > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfBuiltWithId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (self . tokens)) } }
[INFO] [stdout]   |
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] error: `box` patterns have been removed (feature `box_patterns`)
[INFO] [stdout]  --> /opt/rustwide/target/debug/build/hydroflow_plus/5672655b657d1e44/out/lib_pub.rs:1:92750
[INFO] [stdout]   |
[INFO] [stdout] 1 | ...RefCell < HfPlusNode < 'a > >) ; if let HfPlusNode :: Persist (box behind_persist) = inner . replace (HfPlusNode :: Placeholder) {...
[INFO] [stdout]   |                                                                   ^^^
[INFO] [stdout]   |
[INFO] [stdout]   = help: enable feature `deref_patterns` instead and...
[INFO] [stdout] help: ...if possible just remove keyword `box`...
[INFO] [stdout]   |
[INFO] [stdout] 1 - pub use std :: collections :: BTreeMap ; pub use std :: marker :: PhantomData ; pub use hydroflow :: scheduled :: context :: Context ; pub use hydroflow :: scheduled :: graph :: Hydroflow ; pub use hydroflow :: * ; pub use lang :: graph :: { partition_graph , HydroflowGraph } ; pub use proc_macro2 :: TokenStream ; pub use quote :: quote ; pub use stageleft :: runtime_support :: FreeVariable ; pub use stageleft :: Quoted ; pub mod runtime_support { pub use bincode ; } pub mod stream { pub use std :: cell :: RefCell ; pub use std :: hash :: Hash ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow :: bytes :: Bytes ; pub use hydroflow :: futures :: Sink ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: quote ; pub use serde :: de :: DeserializeOwned ; pub use serde :: Serialize ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use syn :: parse_quote ; pub use crate :: builder :: { ClusterIds , FlowLeaves } ; pub use crate :: cycle :: { CycleCollection , CycleComplete } ; pub use crate :: ir :: { DebugInstantiate , HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { CanSend , Location , LocationId } ; pub use crate :: { Cluster , Optional , Singleton } ; pub use crate :: stream :: Unbounded ; pub use crate :: stream :: Bounded ; pub use crate :: stream :: NoTick ; pub use crate :: stream :: Tick ; pub use crate :: stream :: Stream ; # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Stream { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Stream < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Stream { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , C , N > > ,) -> Stream < 'a , (T , O) , W , C , N > where O : Clone , { let other : Optional < 'a , O , Bounded , C , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn cross_product < O > (self , other : Stream < 'a , O , W , C , N >) -> Stream < 'a , (T , O) , W , C , N > where T : Clone , O : Clone , { if self . location_kind != other . location_kind { panic ! ("cross_product must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossProduct (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn union (self , other : Stream < 'a , T , W , C , N >) -> Stream < 'a , T , W , C , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn dest_sink < S : Unpin + Sink < T > + 'a > (self , sink : impl Quoted < 'a , S >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: DestSink { sink : sink . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn first (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } # [doc = " Allow this stream through if the other stream has elements, otherwise the output is empty."] pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } # [doc = " Allow this stream through if the other stream is empty, otherwise the output is empty."] pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn enumerate (self) -> Stream < 'a , (usize , T) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Enumerate (Box :: new (self . ir_node . into_inner ())) ,) } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn sort (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Ord , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Sort (Box :: new (self . ir_node . into_inner ())) ,) } pub fn count (self) -> Singleton < 'a , usize , Bounded , Tick , N > { self . fold (q ! (|| 0usize) , q ! (| count , _ | * count += 1)) } pub fn delta (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } pub fn unique (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Eq + Hash , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unique (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn tick_batch (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_prefix (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { self . tick_batch () . persist () } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn for_each < F : Fn (T) + 'a > (self , f : impl IntoQuotedMut < 'a , F >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: ForEach { input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , f : f . splice () . into () , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Unbounded , NoTick , N > { pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . tick_batch () . continue_if (samples . first ()) . all_ticks () } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Unbounded , NoTick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , C , N : Location > Stream < 'a , T , Bounded , C , N > { pub fn filter_not_in (self , other : Stream < 'a , T , Bounded , C , N >) -> Stream < 'a , T , Bounded , C , N > where T : Eq + Hash , { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Difference (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Stream < 'a , & T , W , C , N > { pub fn cloned (self) -> Stream < 'a , T , W , C , N > { self . map (q ! (| d | d . clone ())) } } # [cfg (stageleft_macro)] impl < 'a , K , V1 , W , C , N : Location > Stream < 'a , (K , V1) , W , C , N > { pub fn join < W2 , V2 > (self , n : Stream < 'a , (K , V2) , W2 , C , N > ,) -> Stream < 'a , (K , (V1 , V2)) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Join (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } pub fn anti_join < W2 > (self , n : Stream < 'a , K , W2 , C , N >) -> Stream < 'a , (K , V1) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("anti_join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: AntiJoin (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , K : Eq + Hash , V , N : Location > Stream < 'a , (K , V) , Bounded , Tick , N > { pub fn fold_keyed < A , I : Fn () -> A + 'a , F : Fn (& mut A , V) + 'a > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , A) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FoldKeyed { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce_keyed < F : Fn (& mut V , V) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , V) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: ReduceKeyed { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } pub fn get_this_crate () -> TokenStream { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , Span :: call_site ()) ; quote ! { # ident } } } } pub fn serialize_bincode < T : Serialize > (is_demux : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if is_demux { parse_quote ! { map (| (id , data) | { (id , # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into ()) }) } } else { parse_quote ! { map (| data | { # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into () }) } } } pub fn deserialize_bincode < T : DeserializeOwned > (tagged : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if tagged { parse_quote ! { map (| res | { let (id , b) = res . unwrap () ; (id , # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& b) . unwrap ()) }) } } else { parse_quote ! { map (| res | { # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& res . unwrap ()) . unwrap () }) } } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn send_bincode < N2 : Location , CoreType > (self , other : & N2 ,) -> Stream < 'a , N :: Out < CoreType > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T > , CoreType : Serialize + DeserializeOwned , { let serialize_pipeline = Some (serialize_bincode :: < CoreType > (N :: is_demux ())) ; let deserialize_pipeline = Some (deserialize_bincode :: < CoreType > (N :: is_tagged ())) ; Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bytes < N2 : Location > (self , other : & N2 ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T > , { Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline : None , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline : if N :: is_tagged () { Some (parse_quote ! (map (| (id , b) | (id , b . unwrap () . freeze ())))) } else { Some (parse_quote ! (map (| b | b . unwrap () . freeze ()))) } , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bincode_interleaved < N2 : Location , Tag , CoreType > (self , other : & N2 ,) -> Stream < 'a , CoreType , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T , Out < CoreType > = (Tag , CoreType) > , CoreType : Serialize + DeserializeOwned , { self . send_bincode :: < N2 , CoreType > (other) . map (q ! (| (_ , b) | b)) } pub fn send_bytes_interleaved < N2 : Location , Tag > (self , other : & N2 ,) -> Stream < 'a , Bytes , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T , Out < Bytes > = (Tag , Bytes) > , { self . send_bytes :: < N2 > (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bincode < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < T > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) > , T : Clone + Serialize + DeserializeOwned , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bincode (other) } pub fn broadcast_bincode_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , T , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) , Out < T > = (Tag , T) > + 'a , T : Clone + Serialize + DeserializeOwned , { self . broadcast_bincode (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bytes < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) > + 'a , T : Clone , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bytes (other) } pub fn broadcast_bytes_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , Bytes , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) , Out < Bytes > = (Tag , Bytes) > + 'a , T : Clone , { self . broadcast_bytes (other) . map (q ! (| (_ , b) | b)) } } } pub use stream :: { Bounded , NoTick , Stream , Tick , Unbounded } ; pub mod singleton { pub use std :: cell :: RefCell ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use crate :: builder :: FlowLeaves ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial , CycleComplete } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: Stream ; pub use crate :: singleton :: CrossResult ; # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Singleton < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Singleton :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } pub use crate :: singleton :: Singleton ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Singleton { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleComplete < 'a > for Singleton < 'a , T , Bounded , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleCollectionWithInitial < 'a > for Singleton < 'a , T , Bounded , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , initial : Self , l : LocationId ,) -> Self { Singleton :: new (l , ir_leaves , HfPlusNode :: Union (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , }) , initial . ir_node . into_inner () . into () ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Singleton < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Singleton { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , U , W , C , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (Self :: other_ir_node (other)) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Singleton < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CrossSingleton (Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , Box :: new (HfPlusNode :: Unpersist (Box :: new (Self :: other_ir_node (other)))) ,))) ,) } } pub use crate :: singleton :: Optional ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Optional { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } pub fn some (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: new (singleton . location_kind , singleton . ir_leaves , singleton . ir_node . into_inner () ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > From < Singleton < 'a , T , W , C , N > > for Optional < 'a , T , W , C , N > { fn from (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: some (singleton) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Optional < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Optional { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn into_stream (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , Tick , N > > ,) -> Optional < 'a , (T , O) , Bounded , Tick , N > where O : Clone , { let other : Optional < 'a , O , Bounded , Tick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn union (self , other : Optional < 'a , T , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Optional < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_samples (self) -> Stream < 'a , T , Unbounded , NoTick , N > { self . latest_tick () . all_ticks () } pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . latest_tick () . continue_if (samples . first ()) . latest () . tick_samples () } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Unbounded , NoTick , N > > ,) -> Optional < 'a , (T , O) , Unbounded , NoTick , N > where O : Clone , { let other : Optional < 'a , O , Unbounded , NoTick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } self . latest_tick () . cross_singleton (other . latest_tick ()) . latest () } } } pub use singleton :: { Optional , Singleton } ; pub mod location { pub use std :: marker :: PhantomData ; pub use crate :: location :: LocationId ; pub use crate :: location :: Location ; pub use crate :: location :: Process ; # [cfg (stageleft_macro)] impl < P > Clone for Process < P > { fn clone (& self) -> Self { Process { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < P > Location for Process < P > { fn id (& self) -> LocationId { LocationId :: Process (self . id) } } pub use crate :: location :: Cluster ; # [cfg (stageleft_macro)] impl < C > Clone for Cluster < C > { fn clone (& self) -> Self { Cluster { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < C > Location for Cluster < C > { fn id (& self) -> LocationId { LocationId :: Cluster (self . id) } } pub use crate :: location :: CanSend ; # [cfg (stageleft_macro)] impl < P1 , P2 > CanSend < Process < P2 > > for Process < P1 > { type In < T > = T ; type Out < T > = T ; fn is_demux () -> bool { false } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < P1 , C2 > CanSend < Cluster < C2 > > for Process < P1 > { type In < T > = (u32 , T) ; type Out < T > = T ; fn is_demux () -> bool { true } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < C1 , P2 > CanSend < Process < P2 > > for Cluster < C1 > { type In < T > = T ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { false } fn is_tagged () -> bool { true } } # [cfg (stageleft_macro)] impl < C1 , C2 > CanSend < Cluster < C2 > > for Cluster < C1 > { type In < T > = (u32 , T) ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { true } fn is_tagged () -> bool { true } } } pub use location :: { Cluster , Process } ; pub mod deploy { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use stageleft :: Quoted ; pub mod graphs { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use super :: { LocalDeploy , Node , ProcessSpec } ; pub use crate :: deploy :: graphs :: SingleProcessGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for SingleProcessGraph { type Process = SingleNode ; type Cluster = SingleNode ; type Meta = () ; type GraphId = () ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { SingleNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { SingleNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , SingleProcessGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> SingleNode { SingleNode { } } } pub use crate :: deploy :: graphs :: SingleNode ; # [cfg (stageleft_macro)] impl Node for SingleNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } pub use crate :: deploy :: graphs :: MultiGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for MultiGraph { type Process = MultiNode ; type Cluster = MultiNode ; type Meta = () ; type GraphId = usize ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { MultiNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { MultiNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , MultiGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> MultiNode { MultiNode { } } } pub use crate :: deploy :: graphs :: MultiNode ; # [cfg (stageleft_macro)] impl Node for MultiNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } } pub use graphs :: * ; pub use crate :: deploy :: LocalDeploy ; pub use crate :: deploy :: Deploy ; # [cfg (stageleft_macro)] impl < 'a , T : Deploy < 'a , Process = N , Cluster = C , Meta = M , GraphId = R > , N : Node < Meta = M > , C : Node < Meta = M > , M : Default , R , > LocalDeploy < 'a > for T { type Process = N ; type Cluster = C ; type Meta = M ; type GraphId = R ; fn has_trivial_node () -> bool { < T as Deploy < 'a > > :: has_trivial_node () } fn trivial_process (id : usize) -> Self :: Process { < T as Deploy < 'a > > :: trivial_process (id) } fn trivial_cluster (id : usize) -> Self :: Cluster { < T as Deploy < 'a > > :: trivail_cluster (id) } } pub use crate :: deploy :: ProcessSpec ; pub use crate :: deploy :: ClusterSpec ; pub use crate :: deploy :: Node ; } pub use deploy :: { ClusterSpec , Deploy , ProcessSpec } ; pub mod cycle { pub use std :: marker :: PhantomData ; pub use crate :: builder :: FlowLeaves ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: cycle :: CycleComplete ; pub use crate :: cycle :: CycleCollection ; pub use crate :: cycle :: CycleCollectionWithInitial ; pub use crate :: cycle :: HfCycle ; # [cfg (stageleft_macro)] impl < 'a , S : CycleComplete < 'a > > HfCycle < 'a , S > { pub fn complete (self , stream : S) { let ident = self . ident ; S :: complete (stream , ident) } } } pub use cycle :: HfCycle ; pub mod builder { pub use std :: cell :: RefCell ; pub use std :: collections :: HashMap ; pub use std :: marker :: PhantomData ; pub use std :: rc :: Rc ; pub use std :: time :: Duration ; pub use hydroflow :: futures :: stream :: Stream as FuturesStream ; pub use hydroflow :: { tokio , tokio_stream } ; pub use internal :: TokenStream ; pub use proc_macro2 :: Span ; pub use quote :: quote ; pub use runtime_support :: FreeVariable ; pub use stageleft :: * ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Cluster , Location , LocationId , Process } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: { HfCycle , Optional , RuntimeContext , Singleton , Stream } ; pub mod built { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use hydroflow_lang :: graph :: { eliminate_extra_unions_tees , HydroflowGraph } ; pub use super :: deploy :: { DeployFlow , DeployResult } ; pub use crate :: deploy :: { ClusterSpec , Deploy , LocalDeploy , ProcessSpec } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Cluster , Process } ; pub use crate :: HfCompiled ; pub use crate :: builder :: built :: BuiltFlow ; # [cfg (stageleft_macro)] impl < 'a > Drop for BuiltFlow < 'a > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped BuiltFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn ir (& self) -> & Vec < HfPlusLeaf < 'a > > { & self . ir } pub fn optimize_with (mut self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> BuiltFlow < 'a > { self . used = true ; BuiltFlow { ir : f (std :: mem :: take (& mut self . ir)) , processes : std :: mem :: take (& mut self . processes) , clusters : std :: mem :: take (& mut self . clusters) , used : false , _phantom : PhantomData , } } } pub fn build_inner (ir : & mut Vec < HfPlusLeaf >) -> BTreeMap < usize , HydroflowGraph > { let mut builders = BTreeMap :: new () ; let mut built_tees = HashMap :: new () ; let mut next_stmt_id = 0 ; for leaf in ir { leaf . emit (& mut builders , & mut built_tees , & mut next_stmt_id) ; } builders . into_iter () . map (| (k , v) | { let (mut flat_graph , _ , _) = v . build () ; eliminate_extra_unions_tees (& mut flat_graph) ; (k , flat_graph) }) . collect () } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn compile_no_network < D : LocalDeploy < 'a > > (mut self) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; HfCompiled { hydroflow_ir : build_inner (& mut self . ir) , extra_stmts : BTreeMap :: new () , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> BuiltFlow < 'a > { self . optimize_with (crate :: persist_pullup :: persist_pullup) } fn into_deploy < D : LocalDeploy < 'a > > (mut self) -> DeployFlow < 'a , D > { self . used = true ; let processes = if D :: has_trivial_node () { self . processes . iter () . map (| id | (* id , D :: trivial_process (* id))) . collect () } else { HashMap :: new () } ; let clusters = if D :: has_trivial_node () { self . clusters . iter () . map (| id | (* id , D :: trivial_cluster (* id))) . collect () } else { HashMap :: new () } ; DeployFlow { ir : std :: mem :: take (& mut self . ir) , nodes : processes , clusters , used : false , _phantom : PhantomData , } } pub fn with_process < P , D : LocalDeploy < 'a > > (self , process : & Process < P > , spec : impl ProcessSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_process (process , spec) } pub fn with_cluster < C , D : LocalDeploy < 'a > > (self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_cluster (cluster , spec) } pub fn compile < D : Deploy < 'a > + 'a > (self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . into_deploy :: < D > () . compile (env) } pub fn deploy < D : Deploy < 'a , CompileEnv = () > + 'a > (self , env : & mut D :: InstantiateEnv ,) -> DeployResult < 'a , D > { self . into_deploy :: < D > () . deploy (env) } } } pub mod deploy { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use proc_macro2 :: Span ; pub use stageleft :: Quoted ; pub use super :: built :: build_inner ; pub use crate :: deploy :: { LocalDeploy , Node } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: { Cluster , ClusterSpec , Deploy , HfCompiled , Process , ProcessSpec } ; pub use crate :: builder :: deploy :: DeployFlow ; # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > Drop for DeployFlow < 'a , D > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped DeployFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > DeployFlow < 'a , D > { pub fn with_process < P > (mut self , process : & Process < P > , spec : impl ProcessSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < P > () . to_string () ; self . nodes . insert (process . id , spec . build (process . id , & tag_name)) ; self } pub fn with_cluster < C > (mut self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < C > () . to_string () ; self . clusters . insert (cluster . id , spec . build (cluster . id , & tag_name)) ; self } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployFlow < 'a , D > { pub fn compile (mut self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; let mut seen_tees : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | leaf . compile_network :: < D > (env , & mut seen_tees , & self . nodes , & self . clusters)) . collect () ; let extra_stmts = self . extra_stmts (env) ; HfCompiled { hydroflow_ir : build_inner (& mut ir_leaves_networked) , extra_stmts , _phantom : PhantomData , } } fn extra_stmts (& self , env : & < D as Deploy < 'a > > :: CompileEnv) -> BTreeMap < usize , Vec < syn :: Stmt > > { let all_locations_count = self . nodes . len () + self . clusters . len () ; let mut extra_stmts : BTreeMap < usize , Vec < syn :: Stmt > > = BTreeMap :: new () ; for & c_id in self . clusters . keys () { let self_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , c_id) , Span :: call_site () ,) ; let self_id_expr = D :: cluster_self_id (env) . splice () ; extra_stmts . entry (c_id) . or_default () . push (syn :: parse_quote ! { let # self_id_ident = # self_id_expr ; }) ; for other_location in 0 .. all_locations_count { let other_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , c_id) , Span :: call_site () ,) ; let other_id_expr = D :: cluster_ids (env , c_id) . splice () ; extra_stmts . entry (other_location) . or_default () . push (syn :: parse_quote ! { let # other_id_ident = # other_id_expr ; }) ; } } extra_stmts } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a , CompileEnv = () > > DeployFlow < 'a , D > { # [must_use] pub fn deploy (mut self , env : & mut D :: InstantiateEnv) -> DeployResult < 'a , D > { self . used = true ; let mut seen_tees_instantiate : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | { leaf . compile_network :: < D > (& () , & mut seen_tees_instantiate , & self . nodes , & self . clusters ,) }) . collect () ; let mut compiled = build_inner (& mut ir_leaves_networked) ; let mut extra_stmts = self . extra_stmts (& ()) ; let mut meta = D :: Meta :: default () ; let (mut processes , mut clusters) = (std :: mem :: take (& mut self . nodes) . into_iter () . map (| (node_id , node) | { node . instantiate (env , & mut meta , compiled . remove (& node_id) . unwrap () , extra_stmts . remove (& node_id) . unwrap_or_default () ,) ; (node_id , node) }) . collect :: < HashMap < _ , _ > > () , std :: mem :: take (& mut self . clusters) . into_iter () . map (| (cluster_id , cluster) | { cluster . instantiate (env , & mut meta , compiled . remove (& cluster_id) . unwrap () , extra_stmts . remove (& cluster_id) . unwrap_or_default () ,) ; (cluster_id , cluster) }) . collect :: < HashMap < _ , _ > > () ,) ; for node in processes . values_mut () { node . update_meta (& meta) ; } for cluster in clusters . values_mut () { cluster . update_meta (& meta) ; } let mut seen_tees_connect = HashMap :: new () ; for leaf in ir_leaves_networked { leaf . connect_network (& mut seen_tees_connect) ; } DeployResult { processes , clusters , } } } pub use crate :: builder :: deploy :: DeployResult ; # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployResult < 'a , D > { pub fn get_process < P > (& self , p : & Process < P >) -> & D :: Process { let id = match p . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . processes . get (& id) . unwrap () } pub fn get_cluster < C > (& self , c : & Cluster < C >) -> & D :: Cluster { let id = match c . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . clusters . get (& id) . unwrap () } } } # [doc = " Tracks the leaves of the dataflow IR. This is referenced by"] # [doc = " `Stream` and `HfCycle` to build the IR. The inner option will"] # [doc = " be set to `None` when this builder is finalized."] pub type FlowLeaves < 'a > = Rc < RefCell < Option < Vec < HfPlusLeaf < 'a > > > > > ; pub use crate :: builder :: ClusterIds ; # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Vec < u32 > > for ClusterIds < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , & 'a Vec < u32 > > for ClusterIds < 'a > { } # [derive (Copy , Clone)] pub struct ClusterSelfId < 'a > { pub id : usize , pub _phantom : PhantomData < & 'a mut & 'a u32 > , } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < u32 > for ClusterSelfId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , u32 > for ClusterSelfId < 'a > { } pub use crate :: builder :: FlowBuilder ; # [cfg (stageleft_macro)] impl < 'a > Drop for FlowBuilder < 'a > { fn drop (& mut self) { if ! self . finalized { panic ! ("Dropped FlowBuilder without finalizing, you may have forgotten to call `with_default_optimize`, `optimize_with`, or `finalize`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > QuotedContext for FlowBuilder < 'a > { fn create () -> Self { FlowBuilder :: new () } } # [cfg (stageleft_macro)] impl < 'a > FlowBuilder < 'a > { # [allow (clippy :: new_without_default)] pub fn new () -> FlowBuilder < 'a > { FlowBuilder { ir_leaves : Rc :: new (RefCell :: new (Some (Vec :: new ()))) , nodes : RefCell :: new (vec ! []) , clusters : RefCell :: new (vec ! []) , cycle_ids : RefCell :: new (HashMap :: new ()) , next_node_id : RefCell :: new (0) , finalized : false , _phantom : PhantomData , } } pub fn finalize (mut self) -> built :: BuiltFlow < 'a > { self . finalized = true ; built :: BuiltFlow { ir : self . ir_leaves . borrow_mut () . take () . unwrap () , processes : self . nodes . replace (vec ! []) , clusters : self . clusters . replace (vec ! []) , used : false , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> built :: BuiltFlow < 'a > { self . finalize () . with_default_optimize () } pub fn optimize_with (self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> built :: BuiltFlow < 'a > { self . finalize () . optimize_with (f) } pub fn ir_leaves (& self) -> & FlowLeaves < 'a > { & self . ir_leaves } pub fn process < P > (& self) -> Process < P > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . nodes . borrow_mut () . push (id) ; Process { id , _phantom : PhantomData , } } pub fn cluster < C > (& self) -> Cluster < C > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . clusters . borrow_mut () . push (id) ; Cluster { id , _phantom : PhantomData , } } pub fn runtime_context (& self) -> RuntimeContext < 'a > { RuntimeContext { _phantom : PhantomData , } } pub fn cluster_members < C > (& self , cluster : & Cluster < C > ,) -> impl Quoted < 'a , & 'a Vec < u32 > > + Copy + 'a { ClusterIds { id : cluster . id , _phantom : PhantomData , } } pub fn cluster_self_id < C > (& self , cluster : & Cluster < C >) -> impl Quoted < 'a , u32 > + Copy + 'a { ClusterSelfId { id : cluster . id , _phantom : PhantomData , } } pub fn spin < L : Location > (& self , on : & L) -> Stream < 'a , () , Unbounded , NoTick , L > { Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Spin () , location_kind : on . id () , })) ,) } pub fn spin_batch < L : Location > (& self , on : & L , batch_size : impl Quoted < 'a , usize > + Copy + 'a ,) -> Stream < 'a , () , Bounded , Tick , L > { self . spin (on) . flat_map (q ! (move | _ | 0 .. batch_size)) . map (q ! (| _ | ())) . tick_batch () } pub fn source_stream < T , E : FuturesStream < Item = T > + Unpin , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Unbounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Stream (e . into ()) , location_kind : on . id () , })) ,) } pub fn source_iter < T , E : IntoIterator < Item = T > , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Bounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , })) ,) } pub fn singleton < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Singleton < 'a , T , Bounded , NoTick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Singleton :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,)))) ,) } pub fn singleton_first_tick < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Optional < 'a , T , Bounded , Tick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,) } pub fn source_interval < L : Location > (& self , on : & L , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , () , Unbounded , NoTick , L > { let interval = interval . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : on . id () , })) ,) } pub fn source_interval_delayed < L : Location > (& self , on : & L , delay : impl Quoted < 'a , Duration > + Copy + 'a , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , tokio :: time :: Instant , Unbounded , NoTick , L > { self . source_stream (on , q ! (tokio_stream :: wrappers :: IntervalStream :: new (tokio :: time :: interval_at (tokio :: time :: Instant :: now () + delay , interval))) ,) . tick_batch () . first () . latest () } pub fn cycle < S : CycleCollection < 'a > > (& self , on : & S :: Location) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , on . id ()) ,) } pub fn cycle_with_initial < S : CycleCollectionWithInitial < 'a > > (& self , on : & S :: Location , initial : S ,) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , initial , on . id ()) ,) } } } pub use builder :: FlowBuilder ; pub mod ir { pub use core :: panic ; pub use std :: cell :: RefCell ; pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow_lang :: graph :: FlatGraphBuilder ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: ToTokens ; pub use syn :: parse_quote ; pub use crate :: deploy :: Deploy ; pub use crate :: location :: LocationId ; pub use crate :: ir :: DebugExpr ; # [cfg (stageleft_macro)] impl From < syn :: Expr > for DebugExpr { fn from (expr : syn :: Expr) -> DebugExpr { DebugExpr (expr) } } # [cfg (stageleft_macro)] impl Deref for DebugExpr { type Target = syn :: Expr ; fn deref (& self) -> & Self :: Target { & self . 0 } } # [cfg (stageleft_macro)] impl ToTokens for DebugExpr { fn to_tokens (& self , tokens : & mut TokenStream) { self . 0 . to_tokens (tokens) ; } } # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugExpr { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "{}" , self . 0 . to_token_stream ()) } } pub use crate :: ir :: DebugInstantiate ; # [cfg (stageleft_macro)] impl < 'a > std :: fmt :: Debug for DebugInstantiate < 'a > { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<network instantiate>") } } pub use crate :: ir :: DebugPipelineFn ; # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugPipelineFn { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<function>") } } pub use crate :: ir :: HfPlusSource ; pub use crate :: ir :: HfPlusLeaf ; # [cfg (stageleft_macro)] impl < 'a > HfPlusLeaf < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . compile_network :: < D > (compile_env , s , nodes , clusters) ; } , seen_tees ,) } pub fn connect_network (self , seen_tees : & mut SeenTees < 'a >) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . connect_network (s) ; } , seen_tees ,) } pub fn transform_children (self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) -> HfPlusLeaf < 'a > { match self { HfPlusLeaf :: ForEach { f , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: ForEach { f , input } } HfPlusLeaf :: DestSink { sink , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: DestSink { sink , input } } HfPlusLeaf :: CycleSink { ident , location_kind , mut input , } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: CycleSink { ident , location_kind , input , } } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) { match self { HfPlusLeaf :: ForEach { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> for_each (# f) ; }) ; } HfPlusLeaf :: DestSink { sink , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink) ; }) ; } HfPlusLeaf :: CycleSink { ident , location_kind , input , } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; assert_eq ! (input_location_id , * location_id , "cycle_sink location mismatch") ; graph_builders . entry (* location_id) . or_default () . add_statement (parse_quote ! { # ident = # input_ident ; }) ; } } } } pub use crate :: ir :: HfPlusNode ; pub type SeenTees < 'a > = HashMap < * const RefCell < HfPlusNode < 'a > > , Rc < RefCell < HfPlusNode < 'a > > > > ; # [cfg (stageleft_macro)] impl < 'a > HfPlusNode < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (& mut self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) { self . transform_children (| n , s | n . compile_network :: < D > (compile_env , s , nodes , clusters) , seen_tees ,) ; if let HfPlusNode :: Network { from_location , to_location , instantiate_fn , .. } = self { let (sink_expr , source_expr , connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { let ((sink , source) , connect_fn) = match (from_location , to_location) { (LocationId :: Process (from) , LocationId :: Process (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: o2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Process (from) , LocationId :: Cluster (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: o2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Process (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: m2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Cluster (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: m2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } } ; (sink , source , connect_fn) } DebugInstantiate :: Finalized (_ , _ , _) => panic ! ("network already finalized") , } ; * instantiate_fn = DebugInstantiate :: Finalized (sink_expr , source_expr , connect_fn) ; } } pub fn connect_network (& mut self , seen_tees : & mut SeenTees < 'a >) { self . transform_children (| n , s | n . connect_network (s) , seen_tees) ; if let HfPlusNode :: Network { instantiate_fn , .. } = self { match instantiate_fn { DebugInstantiate :: Building () => panic ! ("network not built") , DebugInstantiate :: Finalized (_ , _ , ref connect_fn) => { connect_fn () ; } } } } pub fn transform_children (& mut self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) { match self { HfPlusNode :: Placeholder => { panic ! () ; } HfPlusNode :: Source { .. } => { } HfPlusNode :: CycleSource { .. } => { } HfPlusNode :: Tee { inner } => { if let Some (transformed) = seen_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { * inner = transformed . clone () ; } else { let transformed_cell = Rc :: new (RefCell :: new (HfPlusNode :: Placeholder)) ; seen_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , transformed_cell . clone () ,) ; let mut orig = inner . replace (HfPlusNode :: Placeholder) ; transform (& mut orig , seen_tees) ; * transformed_cell . borrow_mut () = orig ; * inner = transformed_cell ; } } HfPlusNode :: Persist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Unpersist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Delta (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Union (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossProduct (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossSingleton (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Join (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Difference (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: AntiJoin (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Map { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FlatMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Filter { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FilterMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Sort (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: DeferTick (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Enumerate (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Inspect { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Unique (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Fold { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FoldKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Reduce { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: ReduceKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Network { input , .. } => { transform (input . as_mut () , seen_tees) ; } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) -> (syn :: Ident , usize) { match self { HfPlusNode :: Placeholder => { panic ! () } HfPlusNode :: Persist (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let persist_id = * next_stmt_id ; * next_stmt_id += 1 ; let persist_ident = syn :: Ident :: new (& format ! ("stream_{}" , persist_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # persist_ident = # inner_ident -> persist ::<'static > () ; }) ; (persist_ident , location) } HfPlusNode :: Unpersist (_) => { panic ! ("Unpersist is a marker node and should have been optimized away. This is likely a compiler bug.") } HfPlusNode :: Delta (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let delta_id = * next_stmt_id ; * next_stmt_id += 1 ; let delta_ident = syn :: Ident :: new (& format ! ("stream_{}" , delta_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # delta_ident = # inner_ident -> multiset_delta () ; }) ; (delta_ident , location) } HfPlusNode :: Source { source , location_kind , } => { let source_id = * next_stmt_id ; * next_stmt_id += 1 ; let source_ident = syn :: Ident :: new (& format ! ("stream_{}" , source_id) , Span :: call_site ()) ; let source_stmt = match source { HfPlusSource :: Stream (expr) => { parse_quote ! { # source_ident = source_stream (# expr) ; } } HfPlusSource :: Iter (expr) => { parse_quote ! { # source_ident = source_iter (# expr) ; } } HfPlusSource :: Interval (expr) => { parse_quote ! { # source_ident = source_interval (# expr) ; } } HfPlusSource :: Spin () => { parse_quote ! { # source_ident = spin () ; } } } ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; graph_builders . entry (* location_id) . or_default () . add_statement (source_stmt) ; (source_ident , * location_id) } HfPlusNode :: CycleSource { ident , location_kind , } => { let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; (ident . clone () , * location_id) } HfPlusNode :: Tee { inner } => { if let Some (ret) = built_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { ret . clone () } else { let (inner_ident , inner_location_id) = inner . borrow () . emit (graph_builders , built_tees , next_stmt_id) ; let tee_id = * next_stmt_id ; * next_stmt_id += 1 ; let tee_ident = syn :: Ident :: new (& format ! ("stream_{}" , tee_id) , Span :: call_site ()) ; let builder = graph_builders . entry (inner_location_id) . or_default () ; builder . add_statement (parse_quote ! { # tee_ident = # inner_ident -> tee () ; }) ; built_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , (tee_ident . clone () , inner_location_id) ,) ; (tee_ident , inner_location_id) } } HfPlusNode :: Union (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "union inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let union_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # union_ident = union () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [0] # union_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # union_ident ; }) ; (union_ident , left_location_id) } HfPlusNode :: CrossSingleton (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "cross_singleton inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let cross_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # cross_ident = cross_singleton () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [input] # cross_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [single] # cross_ident ; }) ; (cross_ident , left_location_id) } HfPlusNode :: CrossProduct (..) | HfPlusNode :: Join (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: CrossProduct (..)) { parse_quote ! (cross_join_multiset) } else { parse_quote ! (join_multiset) } ; let (HfPlusNode :: CrossProduct (left , right) | HfPlusNode :: Join (left , right)) = self else { unreachable ! () } ; let (left_inner , left_was_persist) = if let HfPlusNode :: Persist (left) = left . as_ref () { (left , true) } else { (left , false) } ; let (right_inner , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left_inner . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right_inner . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "join / cross product inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; match (left_was_persist , right_was_persist) { (true , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'static > () ; }) ; } (true , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'tick > () ; }) ; } (false , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } (false , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } } ; builder . add_statement (parse_quote ! { # left_ident -> [0] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Difference (..) | HfPlusNode :: AntiJoin (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Difference (..)) { parse_quote ! (difference_multiset) } else { parse_quote ! (anti_join_multiset) } ; let (HfPlusNode :: Difference (left , right) | HfPlusNode :: AntiJoin (left , right)) = self else { unreachable ! () } ; let (right , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "difference / anti join inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; if right_was_persist { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } else { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } builder . add_statement (parse_quote ! { # left_ident -> [pos] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [neg] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Map { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let map_id = * next_stmt_id ; * next_stmt_id += 1 ; let map_ident = syn :: Ident :: new (& format ! ("stream_{}" , map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # map_ident = # input_ident -> map (# f) ; }) ; (map_ident , input_location_id) } HfPlusNode :: FlatMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let flat_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let flat_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , flat_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # flat_map_ident = # input_ident -> flat_map (# f) ; }) ; (flat_map_ident , input_location_id) } HfPlusNode :: Filter { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_ident = # input_ident -> filter (# f) ; }) ; (filter_ident , input_location_id) } HfPlusNode :: FilterMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_map_ident = # input_ident -> filter_map (# f) ; }) ; (filter_map_ident , input_location_id) } HfPlusNode :: Sort (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sort_id = * next_stmt_id ; * next_stmt_id += 1 ; let sort_ident = syn :: Ident :: new (& format ! ("stream_{}" , sort_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # sort_ident = # input_ident -> sort () ; }) ; (sort_ident , input_location_id) } HfPlusNode :: DeferTick (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let defer_tick_id = * next_stmt_id ; * next_stmt_id += 1 ; let defer_tick_ident = syn :: Ident :: new (& format ! ("stream_{}" , defer_tick_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # defer_tick_ident = # input_ident -> defer_tick_lazy () ; }) ; (defer_tick_ident , input_location_id) } HfPlusNode :: Enumerate (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let enumerate_id = * next_stmt_id ; * next_stmt_id += 1 ; let enumerate_ident = syn :: Ident :: new (& format ! ("stream_{}" , enumerate_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # enumerate_ident = # input_ident -> enumerate () ; }) ; (enumerate_ident , input_location_id) } HfPlusNode :: Inspect { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let inspect_id = * next_stmt_id ; * next_stmt_id += 1 ; let inspect_ident = syn :: Ident :: new (& format ! ("stream_{}" , inspect_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # inspect_ident = # input_ident -> inspect (# f) ; }) ; (inspect_ident , input_location_id) } HfPlusNode :: Unique (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let unique_id = * next_stmt_id ; * next_stmt_id += 1 ; let unique_ident = syn :: Ident :: new (& format ! ("stream_{}" , unique_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # unique_ident = # input_ident -> unique ::<'tick > () ; }) ; (unique_ident , input_location_id) } HfPlusNode :: Fold { .. } | HfPlusNode :: FoldKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Fold { .. }) { parse_quote ! (fold) } else { parse_quote ! (fold_keyed) } ; let (HfPlusNode :: Fold { init , acc , input } | HfPlusNode :: FoldKeyed { init , acc , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let fold_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'static > (# init , # acc) ; }) ; } else { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'tick > (# init , # acc) ; }) ; } (fold_ident , input_location_id) } HfPlusNode :: Reduce { .. } | HfPlusNode :: ReduceKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Reduce { .. }) { parse_quote ! (reduce) } else { parse_quote ! (reduce_keyed) } ; let (HfPlusNode :: Reduce { f , input } | HfPlusNode :: ReduceKeyed { f , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let reduce_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'static > (# f) ; }) ; } else { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'tick > (# f) ; }) ; } (reduce_ident , input_location_id) } HfPlusNode :: Network { from_location : _ , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input , } => { let (sink_expr , source_expr , _connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { panic ! ("Expected the network to be finalized") } DebugInstantiate :: Finalized (sink , source , connect_fn) => { (sink , source , connect_fn) } } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sender_builder = graph_builders . entry (input_location_id) . or_default () ; if let Some (serialize_pipeline) = serialize_pipeline { sender_builder . add_statement (parse_quote ! { # input_ident -> # serialize_pipeline -> dest_sink (# sink_expr) ; }) ; } else { sender_builder . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink_expr) ; }) ; } let to_id = match to_location { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let receiver_builder = graph_builders . entry (* to_id) . or_default () ; let receiver_stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let receiver_stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , receiver_stream_id) , Span :: call_site ()) ; if let Some (deserialize_pipeline) = deserialize_pipeline { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) -> # deserialize_pipeline ; }) ; } else { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) ; }) ; } (receiver_stream_ident , * to_id) } } } } } pub mod persist_pullup { pub use std :: cell :: RefCell ; pub use std :: collections :: HashSet ; pub use std :: ops :: Deref ; pub use crate :: ir :: * ; pub fn persist_pullup_node < 'a > (node : & mut HfPlusNode < 'a > , seen_tees : & mut SeenTees < 'a > , persist_pulled_tees : & mut HashSet < * const RefCell < HfPlusNode < 'a > > > ,) { node . transform_children (| n , s | persist_pullup_node (n , s , persist_pulled_tees) , seen_tees ,) ; match node { HfPlusNode :: Unpersist (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Unpersist (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Delta (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Delta (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Tee { inner } => { if persist_pulled_tees . contains (& (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >)) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } else { let inner_borrow = inner . borrow () ; if let HfPlusNode :: Persist (_) = inner_borrow . deref () { drop (inner_borrow) ; persist_pulled_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >) ; if let HfPlusNode :: Persist (box behind_persist) = inner . replace (HfPlusNode :: Placeholder) { * inner . borrow_mut () = behind_persist ; } else { unreachable ! () } * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } } } HfPlusNode :: Map { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Map { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Map { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: FlatMap { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: FlatMap { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: FlatMap { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Filter { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Filter { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Filter { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Network { input : box HfPlusNode :: Persist (_) , .. } => { if let HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Union (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Union (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Union (left , right))) ; } else { unreachable ! () } } HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: CrossProduct (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,) ,)))) ; } else { unreachable ! () } } HfPlusNode :: Join (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Join (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: Join (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,))))) ; } else { unreachable ! () } } _ => { } } } pub fn persist_pullup (ir : Vec < HfPlusLeaf >) -> Vec < HfPlusLeaf > { let mut seen_tees = Default :: default () ; let mut persist_pulled_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| n , s | persist_pullup_node (n , s , & mut persist_pulled_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn persist_pullup_through_map () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } # [test] fn persist_pullup_behind_tee () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; let before_tee = flow . source_iter (& process , q ! (0 .. 10)) . tick_batch () . persist () ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } } } pub mod profiler { pub use std :: cell :: RefCell ; pub use hydroflow :: futures :: channel :: mpsc :: UnboundedSender ; pub use stageleft :: * ; pub use crate as hydroflow_plus ; pub use crate :: ir :: * ; pub use crate :: RuntimeContext ; pub fn increment_counter (count : & mut u64) { * count += 1 ; } pub fn quoted_any_fn < 'a , F : Fn (& usize) + 'a , Q : IntoQuotedMut < 'a , F > > (q : Q) -> Q { q } # [doc = " Add a profiling node before each node to count the cardinality of its input"] pub fn add_profiling_node < 'a > (node : & mut HfPlusNode < 'a > , _context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > , id : & mut u32 , seen_tees : & mut SeenTees < 'a > ,) { let my_id = * id ; * id += 1 ; node . transform_children (| node , seen_tees | { add_profiling_node (node , _context , counters , counter_queue , id , seen_tees) } , seen_tees ,) ; let orig_node = std :: mem :: replace (node , HfPlusNode :: Placeholder) ; * node = HfPlusNode :: Inspect { f : quoted_any_fn (q ! ({ counter_queue . borrow () . unbounded_send ((my_id as usize , counters . borrow () [my_id as usize])) . unwrap () ; counters . borrow_mut () [my_id as usize] = 0 ; move | _ | { hydroflow_plus :: profiler :: increment_counter (& mut counters . borrow_mut () [my_id as usize] ,) ; } })) . splice () . into () , input : Box :: new (orig_node) , } } # [doc = " Count the cardinality of each input and periodically output to a file"] pub fn profiling < 'a > (ir : Vec < HfPlusLeaf < 'a > > , context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > ,) -> Vec < HfPlusLeaf < 'a > > { let mut id = 0 ; let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | { add_profiling_node (node , context , counters , counter_queue , & mut id , seen_tees) } , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn profiler_wrapping_all_operators () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let runtime_context = flow . runtime_context () ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (& built . ir ()) ; let counters = RuntimeData :: new ("Fake") ; let counter_queue = RuntimeData :: new ("Fake") ; let pushed_down = built . with_default_optimize () . optimize_with (| ir | super :: profiling (ir , runtime_context , counters , counter_queue)) ; insta :: assert_debug_snapshot ! (& pushed_down . ir ()) ; let _ = pushed_down . compile_no_network :: < MultiGraph > () ; } } } pub mod properties { pub use std :: collections :: HashSet ; pub use stageleft :: * ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , SeenTees } ; pub use crate :: properties :: PropertyDatabase ; # [doc = " Allows us to convert the hydroflow datatype for folds to a binary operation for the algebra"] # [doc = " property tests."] # [allow (dead_code)] pub fn convert_hf_to_binary < I , A : Default , F : Fn (& mut A , I) > (f : F) -> impl Fn (I , I) -> A { move | a , b | { let mut acc = Default :: default () ; f (& mut acc , a) ; f (& mut acc , b) ; acc } } # [cfg (stageleft_macro)] impl PropertyDatabase { # [doc = " Tags the expression as commutative."] pub fn add_commutative_tag < 'a , I , A , F : Fn (& mut A , I) , Q : Quoted < 'a , F > + Clone > (& mut self , expr : Q ,) -> Q { let expr_clone = expr . clone () ; self . commutative . insert (expr_clone . splice ()) ; expr } pub fn is_tagged_commutative (& self , expr : & syn :: Expr) -> bool { self . commutative . contains (expr) } } pub fn properties_optimize_node < 'a > (node : & mut HfPlusNode < 'a > , db : & PropertyDatabase , seen_tees : & mut SeenTees < 'a > ,) { node . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , seen_tees ,) ; match node { HfPlusNode :: ReduceKeyed { f , .. } if db . is_tagged_commutative (& f . 0) => { dbg ! ("IDENTIFIED COMMUTATIVE OPTIMIZATION for {:?}" , & f) ; } _ => { } } } pub fn properties_optimize < 'a > (ir : Vec < HfPlusLeaf < 'a > > , db : & PropertyDatabase ,) -> Vec < HfPlusLeaf < 'a > > { let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use super :: * ; use crate :: deploy :: SingleProcessGraph ; use crate :: FlowBuilder ; # [test] fn test_property_database () { let mut db = PropertyDatabase :: default () ; assert ! (! db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; let _ = db . add_commutative_tag (q ! (| a : & mut i32 , b : i32 | * a += b)) ; assert ! (db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; } # [test] fn test_property_optimized () { let flow = FlowBuilder :: new () ; let mut database = PropertyDatabase :: default () ; let process = flow . process :: < () > () ; let counter_func = q ! (| count : & mut i32 , _ | * count += 1) ; let _ = database . add_commutative_tag (counter_func) ; flow . source_iter (& process , q ! (vec ! [])) . map (q ! (| string : String | (string , ()))) . tick_batch () . fold_keyed (q ! (|| 0) , counter_func) . all_ticks () . for_each (q ! (| (string , count) | println ! ("{}: {}" , string , count))) ; let built = flow . finalize () . optimize_with (| ir | properties_optimize (ir , & database)) . with_default_optimize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let _ = built . compile_no_network :: < SingleProcessGraph > () ; } } } pub use crate :: RuntimeContext ; # [cfg (stageleft_macro)] impl Copy for RuntimeContext < '_ > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Context > for RuntimeContext < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (quote ! (& context))) } } pub use crate :: HfCompiled ; # [cfg (stageleft_macro)] impl < 'a , ID > HfCompiled < 'a , ID > { pub fn hydroflow_ir (& self) -> & BTreeMap < usize , HydroflowGraph > { & self . hydroflow_ir } } # [cfg (stageleft_macro)] impl < 'a > HfCompiled < 'a , usize > { pub fn with_dynamic_id (self , id : impl Quoted < 'a , usize >) -> HfBuiltWithId < 'a > { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; let mut conditioned_tokens = None ; for (subgraph_id , flat_graph) in self . hydroflow_ir { let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; let my_extra_stmts = self . extra_stmts . get (& subgraph_id) . cloned () . unwrap_or_default () ; if let Some (conditioned_tokens) = conditioned_tokens . as_mut () { * conditioned_tokens = syn :: parse_quote ! { # conditioned_tokens else if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } } ; } else { conditioned_tokens = Some (syn :: parse_quote ! { if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } }) ; } } let conditioned_tokens : TokenStream = conditioned_tokens . unwrap () ; let id = id . splice () ; HfBuiltWithId { tokens : syn :: parse_quote ! ({ let __given_id = # id ; # conditioned_tokens else { panic ! ("Invalid node id: {}" , __given_id) ; } }) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfCompiled < 'a , () > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfCompiled < 'a , () > { fn to_tokens (mut self) -> (Option < TokenStream > , Option < TokenStream >) { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; if self . hydroflow_ir . len () != 1 { panic ! ("Expected exactly one subgraph in the Hydroflow IR") ; } let flat_graph = self . hydroflow_ir . remove (& 0) . unwrap () ; let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; (None , Some (tokens)) } } pub use crate :: HfBuiltWithId ; # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfBuiltWithId < 'a > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfBuiltWithId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (self . tokens)) } }
[INFO] [stdout] 1 + pub use std :: collections :: BTreeMap ; pub use std :: marker :: PhantomData ; pub use hydroflow :: scheduled :: context :: Context ; pub use hydroflow :: scheduled :: graph :: Hydroflow ; pub use hydroflow :: * ; pub use lang :: graph :: { partition_graph , HydroflowGraph } ; pub use proc_macro2 :: TokenStream ; pub use quote :: quote ; pub use stageleft :: runtime_support :: FreeVariable ; pub use stageleft :: Quoted ; pub mod runtime_support { pub use bincode ; } pub mod stream { pub use std :: cell :: RefCell ; pub use std :: hash :: Hash ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow :: bytes :: Bytes ; pub use hydroflow :: futures :: Sink ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: quote ; pub use serde :: de :: DeserializeOwned ; pub use serde :: Serialize ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use syn :: parse_quote ; pub use crate :: builder :: { ClusterIds , FlowLeaves } ; pub use crate :: cycle :: { CycleCollection , CycleComplete } ; pub use crate :: ir :: { DebugInstantiate , HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { CanSend , Location , LocationId } ; pub use crate :: { Cluster , Optional , Singleton } ; pub use crate :: stream :: Unbounded ; pub use crate :: stream :: Bounded ; pub use crate :: stream :: NoTick ; pub use crate :: stream :: Tick ; pub use crate :: stream :: Stream ; # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Stream { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Stream < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Stream { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , C , N > > ,) -> Stream < 'a , (T , O) , W , C , N > where O : Clone , { let other : Optional < 'a , O , Bounded , C , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn cross_product < O > (self , other : Stream < 'a , O , W , C , N >) -> Stream < 'a , (T , O) , W , C , N > where T : Clone , O : Clone , { if self . location_kind != other . location_kind { panic ! ("cross_product must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossProduct (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn union (self , other : Stream < 'a , T , W , C , N >) -> Stream < 'a , T , W , C , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn dest_sink < S : Unpin + Sink < T > + 'a > (self , sink : impl Quoted < 'a , S >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: DestSink { sink : sink . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn first (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } # [doc = " Allow this stream through if the other stream has elements, otherwise the output is empty."] pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } # [doc = " Allow this stream through if the other stream is empty, otherwise the output is empty."] pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn enumerate (self) -> Stream < 'a , (usize , T) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Enumerate (Box :: new (self . ir_node . into_inner ())) ,) } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn sort (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Ord , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Sort (Box :: new (self . ir_node . into_inner ())) ,) } pub fn count (self) -> Singleton < 'a , usize , Bounded , Tick , N > { self . fold (q ! (|| 0usize) , q ! (| count , _ | * count += 1)) } pub fn delta (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } pub fn unique (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Eq + Hash , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unique (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn tick_batch (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_prefix (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { self . tick_batch () . persist () } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn for_each < F : Fn (T) + 'a > (self , f : impl IntoQuotedMut < 'a , F >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: ForEach { input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , f : f . splice () . into () , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Unbounded , NoTick , N > { pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . tick_batch () . continue_if (samples . first ()) . all_ticks () } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Unbounded , NoTick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , C , N : Location > Stream < 'a , T , Bounded , C , N > { pub fn filter_not_in (self , other : Stream < 'a , T , Bounded , C , N >) -> Stream < 'a , T , Bounded , C , N > where T : Eq + Hash , { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Difference (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Stream < 'a , & T , W , C , N > { pub fn cloned (self) -> Stream < 'a , T , W , C , N > { self . map (q ! (| d | d . clone ())) } } # [cfg (stageleft_macro)] impl < 'a , K , V1 , W , C , N : Location > Stream < 'a , (K , V1) , W , C , N > { pub fn join < W2 , V2 > (self , n : Stream < 'a , (K , V2) , W2 , C , N > ,) -> Stream < 'a , (K , (V1 , V2)) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Join (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } pub fn anti_join < W2 > (self , n : Stream < 'a , K , W2 , C , N >) -> Stream < 'a , (K , V1) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("anti_join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: AntiJoin (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , K : Eq + Hash , V , N : Location > Stream < 'a , (K , V) , Bounded , Tick , N > { pub fn fold_keyed < A , I : Fn () -> A + 'a , F : Fn (& mut A , V) + 'a > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , A) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FoldKeyed { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce_keyed < F : Fn (& mut V , V) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , V) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: ReduceKeyed { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } pub fn get_this_crate () -> TokenStream { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , Span :: call_site ()) ; quote ! { # ident } } } } pub fn serialize_bincode < T : Serialize > (is_demux : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if is_demux { parse_quote ! { map (| (id , data) | { (id , # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into ()) }) } } else { parse_quote ! { map (| data | { # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into () }) } } } pub fn deserialize_bincode < T : DeserializeOwned > (tagged : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if tagged { parse_quote ! { map (| res | { let (id , b) = res . unwrap () ; (id , # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& b) . unwrap ()) }) } } else { parse_quote ! { map (| res | { # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& res . unwrap ()) . unwrap () }) } } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn send_bincode < N2 : Location , CoreType > (self , other : & N2 ,) -> Stream < 'a , N :: Out < CoreType > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T > , CoreType : Serialize + DeserializeOwned , { let serialize_pipeline = Some (serialize_bincode :: < CoreType > (N :: is_demux ())) ; let deserialize_pipeline = Some (deserialize_bincode :: < CoreType > (N :: is_tagged ())) ; Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bytes < N2 : Location > (self , other : & N2 ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T > , { Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline : None , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline : if N :: is_tagged () { Some (parse_quote ! (map (| (id , b) | (id , b . unwrap () . freeze ())))) } else { Some (parse_quote ! (map (| b | b . unwrap () . freeze ()))) } , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bincode_interleaved < N2 : Location , Tag , CoreType > (self , other : & N2 ,) -> Stream < 'a , CoreType , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T , Out < CoreType > = (Tag , CoreType) > , CoreType : Serialize + DeserializeOwned , { self . send_bincode :: < N2 , CoreType > (other) . map (q ! (| (_ , b) | b)) } pub fn send_bytes_interleaved < N2 : Location , Tag > (self , other : & N2 ,) -> Stream < 'a , Bytes , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T , Out < Bytes > = (Tag , Bytes) > , { self . send_bytes :: < N2 > (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bincode < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < T > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) > , T : Clone + Serialize + DeserializeOwned , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bincode (other) } pub fn broadcast_bincode_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , T , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) , Out < T > = (Tag , T) > + 'a , T : Clone + Serialize + DeserializeOwned , { self . broadcast_bincode (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bytes < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) > + 'a , T : Clone , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bytes (other) } pub fn broadcast_bytes_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , Bytes , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) , Out < Bytes > = (Tag , Bytes) > + 'a , T : Clone , { self . broadcast_bytes (other) . map (q ! (| (_ , b) | b)) } } } pub use stream :: { Bounded , NoTick , Stream , Tick , Unbounded } ; pub mod singleton { pub use std :: cell :: RefCell ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use crate :: builder :: FlowLeaves ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial , CycleComplete } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: Stream ; pub use crate :: singleton :: CrossResult ; # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Singleton < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Singleton :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } pub use crate :: singleton :: Singleton ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Singleton { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleComplete < 'a > for Singleton < 'a , T , Bounded , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleCollectionWithInitial < 'a > for Singleton < 'a , T , Bounded , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , initial : Self , l : LocationId ,) -> Self { Singleton :: new (l , ir_leaves , HfPlusNode :: Union (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , }) , initial . ir_node . into_inner () . into () ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Singleton < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Singleton { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , U , W , C , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (Self :: other_ir_node (other)) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Singleton < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CrossSingleton (Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , Box :: new (HfPlusNode :: Unpersist (Box :: new (Self :: other_ir_node (other)))) ,))) ,) } } pub use crate :: singleton :: Optional ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Optional { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } pub fn some (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: new (singleton . location_kind , singleton . ir_leaves , singleton . ir_node . into_inner () ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > From < Singleton < 'a , T , W , C , N > > for Optional < 'a , T , W , C , N > { fn from (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: some (singleton) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Optional < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Optional { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn into_stream (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , Tick , N > > ,) -> Optional < 'a , (T , O) , Bounded , Tick , N > where O : Clone , { let other : Optional < 'a , O , Bounded , Tick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn union (self , other : Optional < 'a , T , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Optional < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_samples (self) -> Stream < 'a , T , Unbounded , NoTick , N > { self . latest_tick () . all_ticks () } pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . latest_tick () . continue_if (samples . first ()) . latest () . tick_samples () } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Unbounded , NoTick , N > > ,) -> Optional < 'a , (T , O) , Unbounded , NoTick , N > where O : Clone , { let other : Optional < 'a , O , Unbounded , NoTick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } self . latest_tick () . cross_singleton (other . latest_tick ()) . latest () } } } pub use singleton :: { Optional , Singleton } ; pub mod location { pub use std :: marker :: PhantomData ; pub use crate :: location :: LocationId ; pub use crate :: location :: Location ; pub use crate :: location :: Process ; # [cfg (stageleft_macro)] impl < P > Clone for Process < P > { fn clone (& self) -> Self { Process { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < P > Location for Process < P > { fn id (& self) -> LocationId { LocationId :: Process (self . id) } } pub use crate :: location :: Cluster ; # [cfg (stageleft_macro)] impl < C > Clone for Cluster < C > { fn clone (& self) -> Self { Cluster { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < C > Location for Cluster < C > { fn id (& self) -> LocationId { LocationId :: Cluster (self . id) } } pub use crate :: location :: CanSend ; # [cfg (stageleft_macro)] impl < P1 , P2 > CanSend < Process < P2 > > for Process < P1 > { type In < T > = T ; type Out < T > = T ; fn is_demux () -> bool { false } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < P1 , C2 > CanSend < Cluster < C2 > > for Process < P1 > { type In < T > = (u32 , T) ; type Out < T > = T ; fn is_demux () -> bool { true } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < C1 , P2 > CanSend < Process < P2 > > for Cluster < C1 > { type In < T > = T ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { false } fn is_tagged () -> bool { true } } # [cfg (stageleft_macro)] impl < C1 , C2 > CanSend < Cluster < C2 > > for Cluster < C1 > { type In < T > = (u32 , T) ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { true } fn is_tagged () -> bool { true } } } pub use location :: { Cluster , Process } ; pub mod deploy { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use stageleft :: Quoted ; pub mod graphs { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use super :: { LocalDeploy , Node , ProcessSpec } ; pub use crate :: deploy :: graphs :: SingleProcessGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for SingleProcessGraph { type Process = SingleNode ; type Cluster = SingleNode ; type Meta = () ; type GraphId = () ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { SingleNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { SingleNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , SingleProcessGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> SingleNode { SingleNode { } } } pub use crate :: deploy :: graphs :: SingleNode ; # [cfg (stageleft_macro)] impl Node for SingleNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } pub use crate :: deploy :: graphs :: MultiGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for MultiGraph { type Process = MultiNode ; type Cluster = MultiNode ; type Meta = () ; type GraphId = usize ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { MultiNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { MultiNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , MultiGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> MultiNode { MultiNode { } } } pub use crate :: deploy :: graphs :: MultiNode ; # [cfg (stageleft_macro)] impl Node for MultiNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } } pub use graphs :: * ; pub use crate :: deploy :: LocalDeploy ; pub use crate :: deploy :: Deploy ; # [cfg (stageleft_macro)] impl < 'a , T : Deploy < 'a , Process = N , Cluster = C , Meta = M , GraphId = R > , N : Node < Meta = M > , C : Node < Meta = M > , M : Default , R , > LocalDeploy < 'a > for T { type Process = N ; type Cluster = C ; type Meta = M ; type GraphId = R ; fn has_trivial_node () -> bool { < T as Deploy < 'a > > :: has_trivial_node () } fn trivial_process (id : usize) -> Self :: Process { < T as Deploy < 'a > > :: trivial_process (id) } fn trivial_cluster (id : usize) -> Self :: Cluster { < T as Deploy < 'a > > :: trivail_cluster (id) } } pub use crate :: deploy :: ProcessSpec ; pub use crate :: deploy :: ClusterSpec ; pub use crate :: deploy :: Node ; } pub use deploy :: { ClusterSpec , Deploy , ProcessSpec } ; pub mod cycle { pub use std :: marker :: PhantomData ; pub use crate :: builder :: FlowLeaves ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: cycle :: CycleComplete ; pub use crate :: cycle :: CycleCollection ; pub use crate :: cycle :: CycleCollectionWithInitial ; pub use crate :: cycle :: HfCycle ; # [cfg (stageleft_macro)] impl < 'a , S : CycleComplete < 'a > > HfCycle < 'a , S > { pub fn complete (self , stream : S) { let ident = self . ident ; S :: complete (stream , ident) } } } pub use cycle :: HfCycle ; pub mod builder { pub use std :: cell :: RefCell ; pub use std :: collections :: HashMap ; pub use std :: marker :: PhantomData ; pub use std :: rc :: Rc ; pub use std :: time :: Duration ; pub use hydroflow :: futures :: stream :: Stream as FuturesStream ; pub use hydroflow :: { tokio , tokio_stream } ; pub use internal :: TokenStream ; pub use proc_macro2 :: Span ; pub use quote :: quote ; pub use runtime_support :: FreeVariable ; pub use stageleft :: * ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Cluster , Location , LocationId , Process } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: { HfCycle , Optional , RuntimeContext , Singleton , Stream } ; pub mod built { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use hydroflow_lang :: graph :: { eliminate_extra_unions_tees , HydroflowGraph } ; pub use super :: deploy :: { DeployFlow , DeployResult } ; pub use crate :: deploy :: { ClusterSpec , Deploy , LocalDeploy , ProcessSpec } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Cluster , Process } ; pub use crate :: HfCompiled ; pub use crate :: builder :: built :: BuiltFlow ; # [cfg (stageleft_macro)] impl < 'a > Drop for BuiltFlow < 'a > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped BuiltFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn ir (& self) -> & Vec < HfPlusLeaf < 'a > > { & self . ir } pub fn optimize_with (mut self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> BuiltFlow < 'a > { self . used = true ; BuiltFlow { ir : f (std :: mem :: take (& mut self . ir)) , processes : std :: mem :: take (& mut self . processes) , clusters : std :: mem :: take (& mut self . clusters) , used : false , _phantom : PhantomData , } } } pub fn build_inner (ir : & mut Vec < HfPlusLeaf >) -> BTreeMap < usize , HydroflowGraph > { let mut builders = BTreeMap :: new () ; let mut built_tees = HashMap :: new () ; let mut next_stmt_id = 0 ; for leaf in ir { leaf . emit (& mut builders , & mut built_tees , & mut next_stmt_id) ; } builders . into_iter () . map (| (k , v) | { let (mut flat_graph , _ , _) = v . build () ; eliminate_extra_unions_tees (& mut flat_graph) ; (k , flat_graph) }) . collect () } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn compile_no_network < D : LocalDeploy < 'a > > (mut self) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; HfCompiled { hydroflow_ir : build_inner (& mut self . ir) , extra_stmts : BTreeMap :: new () , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> BuiltFlow < 'a > { self . optimize_with (crate :: persist_pullup :: persist_pullup) } fn into_deploy < D : LocalDeploy < 'a > > (mut self) -> DeployFlow < 'a , D > { self . used = true ; let processes = if D :: has_trivial_node () { self . processes . iter () . map (| id | (* id , D :: trivial_process (* id))) . collect () } else { HashMap :: new () } ; let clusters = if D :: has_trivial_node () { self . clusters . iter () . map (| id | (* id , D :: trivial_cluster (* id))) . collect () } else { HashMap :: new () } ; DeployFlow { ir : std :: mem :: take (& mut self . ir) , nodes : processes , clusters , used : false , _phantom : PhantomData , } } pub fn with_process < P , D : LocalDeploy < 'a > > (self , process : & Process < P > , spec : impl ProcessSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_process (process , spec) } pub fn with_cluster < C , D : LocalDeploy < 'a > > (self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_cluster (cluster , spec) } pub fn compile < D : Deploy < 'a > + 'a > (self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . into_deploy :: < D > () . compile (env) } pub fn deploy < D : Deploy < 'a , CompileEnv = () > + 'a > (self , env : & mut D :: InstantiateEnv ,) -> DeployResult < 'a , D > { self . into_deploy :: < D > () . deploy (env) } } } pub mod deploy { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use proc_macro2 :: Span ; pub use stageleft :: Quoted ; pub use super :: built :: build_inner ; pub use crate :: deploy :: { LocalDeploy , Node } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: { Cluster , ClusterSpec , Deploy , HfCompiled , Process , ProcessSpec } ; pub use crate :: builder :: deploy :: DeployFlow ; # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > Drop for DeployFlow < 'a , D > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped DeployFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > DeployFlow < 'a , D > { pub fn with_process < P > (mut self , process : & Process < P > , spec : impl ProcessSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < P > () . to_string () ; self . nodes . insert (process . id , spec . build (process . id , & tag_name)) ; self } pub fn with_cluster < C > (mut self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < C > () . to_string () ; self . clusters . insert (cluster . id , spec . build (cluster . id , & tag_name)) ; self } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployFlow < 'a , D > { pub fn compile (mut self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; let mut seen_tees : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | leaf . compile_network :: < D > (env , & mut seen_tees , & self . nodes , & self . clusters)) . collect () ; let extra_stmts = self . extra_stmts (env) ; HfCompiled { hydroflow_ir : build_inner (& mut ir_leaves_networked) , extra_stmts , _phantom : PhantomData , } } fn extra_stmts (& self , env : & < D as Deploy < 'a > > :: CompileEnv) -> BTreeMap < usize , Vec < syn :: Stmt > > { let all_locations_count = self . nodes . len () + self . clusters . len () ; let mut extra_stmts : BTreeMap < usize , Vec < syn :: Stmt > > = BTreeMap :: new () ; for & c_id in self . clusters . keys () { let self_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , c_id) , Span :: call_site () ,) ; let self_id_expr = D :: cluster_self_id (env) . splice () ; extra_stmts . entry (c_id) . or_default () . push (syn :: parse_quote ! { let # self_id_ident = # self_id_expr ; }) ; for other_location in 0 .. all_locations_count { let other_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , c_id) , Span :: call_site () ,) ; let other_id_expr = D :: cluster_ids (env , c_id) . splice () ; extra_stmts . entry (other_location) . or_default () . push (syn :: parse_quote ! { let # other_id_ident = # other_id_expr ; }) ; } } extra_stmts } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a , CompileEnv = () > > DeployFlow < 'a , D > { # [must_use] pub fn deploy (mut self , env : & mut D :: InstantiateEnv) -> DeployResult < 'a , D > { self . used = true ; let mut seen_tees_instantiate : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | { leaf . compile_network :: < D > (& () , & mut seen_tees_instantiate , & self . nodes , & self . clusters ,) }) . collect () ; let mut compiled = build_inner (& mut ir_leaves_networked) ; let mut extra_stmts = self . extra_stmts (& ()) ; let mut meta = D :: Meta :: default () ; let (mut processes , mut clusters) = (std :: mem :: take (& mut self . nodes) . into_iter () . map (| (node_id , node) | { node . instantiate (env , & mut meta , compiled . remove (& node_id) . unwrap () , extra_stmts . remove (& node_id) . unwrap_or_default () ,) ; (node_id , node) }) . collect :: < HashMap < _ , _ > > () , std :: mem :: take (& mut self . clusters) . into_iter () . map (| (cluster_id , cluster) | { cluster . instantiate (env , & mut meta , compiled . remove (& cluster_id) . unwrap () , extra_stmts . remove (& cluster_id) . unwrap_or_default () ,) ; (cluster_id , cluster) }) . collect :: < HashMap < _ , _ > > () ,) ; for node in processes . values_mut () { node . update_meta (& meta) ; } for cluster in clusters . values_mut () { cluster . update_meta (& meta) ; } let mut seen_tees_connect = HashMap :: new () ; for leaf in ir_leaves_networked { leaf . connect_network (& mut seen_tees_connect) ; } DeployResult { processes , clusters , } } } pub use crate :: builder :: deploy :: DeployResult ; # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployResult < 'a , D > { pub fn get_process < P > (& self , p : & Process < P >) -> & D :: Process { let id = match p . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . processes . get (& id) . unwrap () } pub fn get_cluster < C > (& self , c : & Cluster < C >) -> & D :: Cluster { let id = match c . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . clusters . get (& id) . unwrap () } } } # [doc = " Tracks the leaves of the dataflow IR. This is referenced by"] # [doc = " `Stream` and `HfCycle` to build the IR. The inner option will"] # [doc = " be set to `None` when this builder is finalized."] pub type FlowLeaves < 'a > = Rc < RefCell < Option < Vec < HfPlusLeaf < 'a > > > > > ; pub use crate :: builder :: ClusterIds ; # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Vec < u32 > > for ClusterIds < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , & 'a Vec < u32 > > for ClusterIds < 'a > { } # [derive (Copy , Clone)] pub struct ClusterSelfId < 'a > { pub id : usize , pub _phantom : PhantomData < & 'a mut & 'a u32 > , } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < u32 > for ClusterSelfId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , u32 > for ClusterSelfId < 'a > { } pub use crate :: builder :: FlowBuilder ; # [cfg (stageleft_macro)] impl < 'a > Drop for FlowBuilder < 'a > { fn drop (& mut self) { if ! self . finalized { panic ! ("Dropped FlowBuilder without finalizing, you may have forgotten to call `with_default_optimize`, `optimize_with`, or `finalize`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > QuotedContext for FlowBuilder < 'a > { fn create () -> Self { FlowBuilder :: new () } } # [cfg (stageleft_macro)] impl < 'a > FlowBuilder < 'a > { # [allow (clippy :: new_without_default)] pub fn new () -> FlowBuilder < 'a > { FlowBuilder { ir_leaves : Rc :: new (RefCell :: new (Some (Vec :: new ()))) , nodes : RefCell :: new (vec ! []) , clusters : RefCell :: new (vec ! []) , cycle_ids : RefCell :: new (HashMap :: new ()) , next_node_id : RefCell :: new (0) , finalized : false , _phantom : PhantomData , } } pub fn finalize (mut self) -> built :: BuiltFlow < 'a > { self . finalized = true ; built :: BuiltFlow { ir : self . ir_leaves . borrow_mut () . take () . unwrap () , processes : self . nodes . replace (vec ! []) , clusters : self . clusters . replace (vec ! []) , used : false , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> built :: BuiltFlow < 'a > { self . finalize () . with_default_optimize () } pub fn optimize_with (self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> built :: BuiltFlow < 'a > { self . finalize () . optimize_with (f) } pub fn ir_leaves (& self) -> & FlowLeaves < 'a > { & self . ir_leaves } pub fn process < P > (& self) -> Process < P > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . nodes . borrow_mut () . push (id) ; Process { id , _phantom : PhantomData , } } pub fn cluster < C > (& self) -> Cluster < C > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . clusters . borrow_mut () . push (id) ; Cluster { id , _phantom : PhantomData , } } pub fn runtime_context (& self) -> RuntimeContext < 'a > { RuntimeContext { _phantom : PhantomData , } } pub fn cluster_members < C > (& self , cluster : & Cluster < C > ,) -> impl Quoted < 'a , & 'a Vec < u32 > > + Copy + 'a { ClusterIds { id : cluster . id , _phantom : PhantomData , } } pub fn cluster_self_id < C > (& self , cluster : & Cluster < C >) -> impl Quoted < 'a , u32 > + Copy + 'a { ClusterSelfId { id : cluster . id , _phantom : PhantomData , } } pub fn spin < L : Location > (& self , on : & L) -> Stream < 'a , () , Unbounded , NoTick , L > { Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Spin () , location_kind : on . id () , })) ,) } pub fn spin_batch < L : Location > (& self , on : & L , batch_size : impl Quoted < 'a , usize > + Copy + 'a ,) -> Stream < 'a , () , Bounded , Tick , L > { self . spin (on) . flat_map (q ! (move | _ | 0 .. batch_size)) . map (q ! (| _ | ())) . tick_batch () } pub fn source_stream < T , E : FuturesStream < Item = T > + Unpin , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Unbounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Stream (e . into ()) , location_kind : on . id () , })) ,) } pub fn source_iter < T , E : IntoIterator < Item = T > , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Bounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , })) ,) } pub fn singleton < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Singleton < 'a , T , Bounded , NoTick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Singleton :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,)))) ,) } pub fn singleton_first_tick < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Optional < 'a , T , Bounded , Tick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,) } pub fn source_interval < L : Location > (& self , on : & L , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , () , Unbounded , NoTick , L > { let interval = interval . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : on . id () , })) ,) } pub fn source_interval_delayed < L : Location > (& self , on : & L , delay : impl Quoted < 'a , Duration > + Copy + 'a , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , tokio :: time :: Instant , Unbounded , NoTick , L > { self . source_stream (on , q ! (tokio_stream :: wrappers :: IntervalStream :: new (tokio :: time :: interval_at (tokio :: time :: Instant :: now () + delay , interval))) ,) . tick_batch () . first () . latest () } pub fn cycle < S : CycleCollection < 'a > > (& self , on : & S :: Location) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , on . id ()) ,) } pub fn cycle_with_initial < S : CycleCollectionWithInitial < 'a > > (& self , on : & S :: Location , initial : S ,) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , initial , on . id ()) ,) } } } pub use builder :: FlowBuilder ; pub mod ir { pub use core :: panic ; pub use std :: cell :: RefCell ; pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow_lang :: graph :: FlatGraphBuilder ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: ToTokens ; pub use syn :: parse_quote ; pub use crate :: deploy :: Deploy ; pub use crate :: location :: LocationId ; pub use crate :: ir :: DebugExpr ; # [cfg (stageleft_macro)] impl From < syn :: Expr > for DebugExpr { fn from (expr : syn :: Expr) -> DebugExpr { DebugExpr (expr) } } # [cfg (stageleft_macro)] impl Deref for DebugExpr { type Target = syn :: Expr ; fn deref (& self) -> & Self :: Target { & self . 0 } } # [cfg (stageleft_macro)] impl ToTokens for DebugExpr { fn to_tokens (& self , tokens : & mut TokenStream) { self . 0 . to_tokens (tokens) ; } } # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugExpr { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "{}" , self . 0 . to_token_stream ()) } } pub use crate :: ir :: DebugInstantiate ; # [cfg (stageleft_macro)] impl < 'a > std :: fmt :: Debug for DebugInstantiate < 'a > { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<network instantiate>") } } pub use crate :: ir :: DebugPipelineFn ; # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugPipelineFn { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<function>") } } pub use crate :: ir :: HfPlusSource ; pub use crate :: ir :: HfPlusLeaf ; # [cfg (stageleft_macro)] impl < 'a > HfPlusLeaf < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . compile_network :: < D > (compile_env , s , nodes , clusters) ; } , seen_tees ,) } pub fn connect_network (self , seen_tees : & mut SeenTees < 'a >) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . connect_network (s) ; } , seen_tees ,) } pub fn transform_children (self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) -> HfPlusLeaf < 'a > { match self { HfPlusLeaf :: ForEach { f , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: ForEach { f , input } } HfPlusLeaf :: DestSink { sink , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: DestSink { sink , input } } HfPlusLeaf :: CycleSink { ident , location_kind , mut input , } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: CycleSink { ident , location_kind , input , } } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) { match self { HfPlusLeaf :: ForEach { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> for_each (# f) ; }) ; } HfPlusLeaf :: DestSink { sink , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink) ; }) ; } HfPlusLeaf :: CycleSink { ident , location_kind , input , } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; assert_eq ! (input_location_id , * location_id , "cycle_sink location mismatch") ; graph_builders . entry (* location_id) . or_default () . add_statement (parse_quote ! { # ident = # input_ident ; }) ; } } } } pub use crate :: ir :: HfPlusNode ; pub type SeenTees < 'a > = HashMap < * const RefCell < HfPlusNode < 'a > > , Rc < RefCell < HfPlusNode < 'a > > > > ; # [cfg (stageleft_macro)] impl < 'a > HfPlusNode < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (& mut self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) { self . transform_children (| n , s | n . compile_network :: < D > (compile_env , s , nodes , clusters) , seen_tees ,) ; if let HfPlusNode :: Network { from_location , to_location , instantiate_fn , .. } = self { let (sink_expr , source_expr , connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { let ((sink , source) , connect_fn) = match (from_location , to_location) { (LocationId :: Process (from) , LocationId :: Process (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: o2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Process (from) , LocationId :: Cluster (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: o2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Process (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: m2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Cluster (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: m2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } } ; (sink , source , connect_fn) } DebugInstantiate :: Finalized (_ , _ , _) => panic ! ("network already finalized") , } ; * instantiate_fn = DebugInstantiate :: Finalized (sink_expr , source_expr , connect_fn) ; } } pub fn connect_network (& mut self , seen_tees : & mut SeenTees < 'a >) { self . transform_children (| n , s | n . connect_network (s) , seen_tees) ; if let HfPlusNode :: Network { instantiate_fn , .. } = self { match instantiate_fn { DebugInstantiate :: Building () => panic ! ("network not built") , DebugInstantiate :: Finalized (_ , _ , ref connect_fn) => { connect_fn () ; } } } } pub fn transform_children (& mut self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) { match self { HfPlusNode :: Placeholder => { panic ! () ; } HfPlusNode :: Source { .. } => { } HfPlusNode :: CycleSource { .. } => { } HfPlusNode :: Tee { inner } => { if let Some (transformed) = seen_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { * inner = transformed . clone () ; } else { let transformed_cell = Rc :: new (RefCell :: new (HfPlusNode :: Placeholder)) ; seen_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , transformed_cell . clone () ,) ; let mut orig = inner . replace (HfPlusNode :: Placeholder) ; transform (& mut orig , seen_tees) ; * transformed_cell . borrow_mut () = orig ; * inner = transformed_cell ; } } HfPlusNode :: Persist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Unpersist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Delta (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Union (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossProduct (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossSingleton (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Join (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Difference (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: AntiJoin (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Map { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FlatMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Filter { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FilterMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Sort (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: DeferTick (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Enumerate (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Inspect { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Unique (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Fold { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FoldKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Reduce { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: ReduceKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Network { input , .. } => { transform (input . as_mut () , seen_tees) ; } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) -> (syn :: Ident , usize) { match self { HfPlusNode :: Placeholder => { panic ! () } HfPlusNode :: Persist (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let persist_id = * next_stmt_id ; * next_stmt_id += 1 ; let persist_ident = syn :: Ident :: new (& format ! ("stream_{}" , persist_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # persist_ident = # inner_ident -> persist ::<'static > () ; }) ; (persist_ident , location) } HfPlusNode :: Unpersist (_) => { panic ! ("Unpersist is a marker node and should have been optimized away. This is likely a compiler bug.") } HfPlusNode :: Delta (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let delta_id = * next_stmt_id ; * next_stmt_id += 1 ; let delta_ident = syn :: Ident :: new (& format ! ("stream_{}" , delta_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # delta_ident = # inner_ident -> multiset_delta () ; }) ; (delta_ident , location) } HfPlusNode :: Source { source , location_kind , } => { let source_id = * next_stmt_id ; * next_stmt_id += 1 ; let source_ident = syn :: Ident :: new (& format ! ("stream_{}" , source_id) , Span :: call_site ()) ; let source_stmt = match source { HfPlusSource :: Stream (expr) => { parse_quote ! { # source_ident = source_stream (# expr) ; } } HfPlusSource :: Iter (expr) => { parse_quote ! { # source_ident = source_iter (# expr) ; } } HfPlusSource :: Interval (expr) => { parse_quote ! { # source_ident = source_interval (# expr) ; } } HfPlusSource :: Spin () => { parse_quote ! { # source_ident = spin () ; } } } ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; graph_builders . entry (* location_id) . or_default () . add_statement (source_stmt) ; (source_ident , * location_id) } HfPlusNode :: CycleSource { ident , location_kind , } => { let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; (ident . clone () , * location_id) } HfPlusNode :: Tee { inner } => { if let Some (ret) = built_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { ret . clone () } else { let (inner_ident , inner_location_id) = inner . borrow () . emit (graph_builders , built_tees , next_stmt_id) ; let tee_id = * next_stmt_id ; * next_stmt_id += 1 ; let tee_ident = syn :: Ident :: new (& format ! ("stream_{}" , tee_id) , Span :: call_site ()) ; let builder = graph_builders . entry (inner_location_id) . or_default () ; builder . add_statement (parse_quote ! { # tee_ident = # inner_ident -> tee () ; }) ; built_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , (tee_ident . clone () , inner_location_id) ,) ; (tee_ident , inner_location_id) } } HfPlusNode :: Union (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "union inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let union_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # union_ident = union () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [0] # union_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # union_ident ; }) ; (union_ident , left_location_id) } HfPlusNode :: CrossSingleton (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "cross_singleton inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let cross_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # cross_ident = cross_singleton () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [input] # cross_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [single] # cross_ident ; }) ; (cross_ident , left_location_id) } HfPlusNode :: CrossProduct (..) | HfPlusNode :: Join (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: CrossProduct (..)) { parse_quote ! (cross_join_multiset) } else { parse_quote ! (join_multiset) } ; let (HfPlusNode :: CrossProduct (left , right) | HfPlusNode :: Join (left , right)) = self else { unreachable ! () } ; let (left_inner , left_was_persist) = if let HfPlusNode :: Persist (left) = left . as_ref () { (left , true) } else { (left , false) } ; let (right_inner , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left_inner . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right_inner . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "join / cross product inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; match (left_was_persist , right_was_persist) { (true , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'static > () ; }) ; } (true , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'tick > () ; }) ; } (false , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } (false , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } } ; builder . add_statement (parse_quote ! { # left_ident -> [0] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Difference (..) | HfPlusNode :: AntiJoin (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Difference (..)) { parse_quote ! (difference_multiset) } else { parse_quote ! (anti_join_multiset) } ; let (HfPlusNode :: Difference (left , right) | HfPlusNode :: AntiJoin (left , right)) = self else { unreachable ! () } ; let (right , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "difference / anti join inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; if right_was_persist { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } else { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } builder . add_statement (parse_quote ! { # left_ident -> [pos] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [neg] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Map { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let map_id = * next_stmt_id ; * next_stmt_id += 1 ; let map_ident = syn :: Ident :: new (& format ! ("stream_{}" , map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # map_ident = # input_ident -> map (# f) ; }) ; (map_ident , input_location_id) } HfPlusNode :: FlatMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let flat_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let flat_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , flat_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # flat_map_ident = # input_ident -> flat_map (# f) ; }) ; (flat_map_ident , input_location_id) } HfPlusNode :: Filter { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_ident = # input_ident -> filter (# f) ; }) ; (filter_ident , input_location_id) } HfPlusNode :: FilterMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_map_ident = # input_ident -> filter_map (# f) ; }) ; (filter_map_ident , input_location_id) } HfPlusNode :: Sort (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sort_id = * next_stmt_id ; * next_stmt_id += 1 ; let sort_ident = syn :: Ident :: new (& format ! ("stream_{}" , sort_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # sort_ident = # input_ident -> sort () ; }) ; (sort_ident , input_location_id) } HfPlusNode :: DeferTick (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let defer_tick_id = * next_stmt_id ; * next_stmt_id += 1 ; let defer_tick_ident = syn :: Ident :: new (& format ! ("stream_{}" , defer_tick_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # defer_tick_ident = # input_ident -> defer_tick_lazy () ; }) ; (defer_tick_ident , input_location_id) } HfPlusNode :: Enumerate (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let enumerate_id = * next_stmt_id ; * next_stmt_id += 1 ; let enumerate_ident = syn :: Ident :: new (& format ! ("stream_{}" , enumerate_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # enumerate_ident = # input_ident -> enumerate () ; }) ; (enumerate_ident , input_location_id) } HfPlusNode :: Inspect { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let inspect_id = * next_stmt_id ; * next_stmt_id += 1 ; let inspect_ident = syn :: Ident :: new (& format ! ("stream_{}" , inspect_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # inspect_ident = # input_ident -> inspect (# f) ; }) ; (inspect_ident , input_location_id) } HfPlusNode :: Unique (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let unique_id = * next_stmt_id ; * next_stmt_id += 1 ; let unique_ident = syn :: Ident :: new (& format ! ("stream_{}" , unique_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # unique_ident = # input_ident -> unique ::<'tick > () ; }) ; (unique_ident , input_location_id) } HfPlusNode :: Fold { .. } | HfPlusNode :: FoldKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Fold { .. }) { parse_quote ! (fold) } else { parse_quote ! (fold_keyed) } ; let (HfPlusNode :: Fold { init , acc , input } | HfPlusNode :: FoldKeyed { init , acc , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let fold_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'static > (# init , # acc) ; }) ; } else { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'tick > (# init , # acc) ; }) ; } (fold_ident , input_location_id) } HfPlusNode :: Reduce { .. } | HfPlusNode :: ReduceKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Reduce { .. }) { parse_quote ! (reduce) } else { parse_quote ! (reduce_keyed) } ; let (HfPlusNode :: Reduce { f , input } | HfPlusNode :: ReduceKeyed { f , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let reduce_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'static > (# f) ; }) ; } else { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'tick > (# f) ; }) ; } (reduce_ident , input_location_id) } HfPlusNode :: Network { from_location : _ , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input , } => { let (sink_expr , source_expr , _connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { panic ! ("Expected the network to be finalized") } DebugInstantiate :: Finalized (sink , source , connect_fn) => { (sink , source , connect_fn) } } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sender_builder = graph_builders . entry (input_location_id) . or_default () ; if let Some (serialize_pipeline) = serialize_pipeline { sender_builder . add_statement (parse_quote ! { # input_ident -> # serialize_pipeline -> dest_sink (# sink_expr) ; }) ; } else { sender_builder . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink_expr) ; }) ; } let to_id = match to_location { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let receiver_builder = graph_builders . entry (* to_id) . or_default () ; let receiver_stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let receiver_stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , receiver_stream_id) , Span :: call_site ()) ; if let Some (deserialize_pipeline) = deserialize_pipeline { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) -> # deserialize_pipeline ; }) ; } else { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) ; }) ; } (receiver_stream_ident , * to_id) } } } } } pub mod persist_pullup { pub use std :: cell :: RefCell ; pub use std :: collections :: HashSet ; pub use std :: ops :: Deref ; pub use crate :: ir :: * ; pub fn persist_pullup_node < 'a > (node : & mut HfPlusNode < 'a > , seen_tees : & mut SeenTees < 'a > , persist_pulled_tees : & mut HashSet < * const RefCell < HfPlusNode < 'a > > > ,) { node . transform_children (| n , s | persist_pullup_node (n , s , persist_pulled_tees) , seen_tees ,) ; match node { HfPlusNode :: Unpersist (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Unpersist (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Delta (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Delta (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Tee { inner } => { if persist_pulled_tees . contains (& (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >)) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } else { let inner_borrow = inner . borrow () ; if let HfPlusNode :: Persist (_) = inner_borrow . deref () { drop (inner_borrow) ; persist_pulled_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >) ; if let HfPlusNode :: Persist (behind_persist) = inner . replace (HfPlusNode :: Placeholder) { * inner . borrow_mut () = behind_persist ; } else { unreachable ! () } * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } } } HfPlusNode :: Map { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Map { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Map { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: FlatMap { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: FlatMap { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: FlatMap { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Filter { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Filter { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Filter { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Network { input : box HfPlusNode :: Persist (_) , .. } => { if let HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Union (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Union (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Union (left , right))) ; } else { unreachable ! () } } HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: CrossProduct (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,) ,)))) ; } else { unreachable ! () } } HfPlusNode :: Join (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Join (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: Join (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,))))) ; } else { unreachable ! () } } _ => { } } } pub fn persist_pullup (ir : Vec < HfPlusLeaf >) -> Vec < HfPlusLeaf > { let mut seen_tees = Default :: default () ; let mut persist_pulled_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| n , s | persist_pullup_node (n , s , & mut persist_pulled_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn persist_pullup_through_map () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } # [test] fn persist_pullup_behind_tee () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; let before_tee = flow . source_iter (& process , q ! (0 .. 10)) . tick_batch () . persist () ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } } } pub mod profiler { pub use std :: cell :: RefCell ; pub use hydroflow :: futures :: channel :: mpsc :: UnboundedSender ; pub use stageleft :: * ; pub use crate as hydroflow_plus ; pub use crate :: ir :: * ; pub use crate :: RuntimeContext ; pub fn increment_counter (count : & mut u64) { * count += 1 ; } pub fn quoted_any_fn < 'a , F : Fn (& usize) + 'a , Q : IntoQuotedMut < 'a , F > > (q : Q) -> Q { q } # [doc = " Add a profiling node before each node to count the cardinality of its input"] pub fn add_profiling_node < 'a > (node : & mut HfPlusNode < 'a > , _context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > , id : & mut u32 , seen_tees : & mut SeenTees < 'a > ,) { let my_id = * id ; * id += 1 ; node . transform_children (| node , seen_tees | { add_profiling_node (node , _context , counters , counter_queue , id , seen_tees) } , seen_tees ,) ; let orig_node = std :: mem :: replace (node , HfPlusNode :: Placeholder) ; * node = HfPlusNode :: Inspect { f : quoted_any_fn (q ! ({ counter_queue . borrow () . unbounded_send ((my_id as usize , counters . borrow () [my_id as usize])) . unwrap () ; counters . borrow_mut () [my_id as usize] = 0 ; move | _ | { hydroflow_plus :: profiler :: increment_counter (& mut counters . borrow_mut () [my_id as usize] ,) ; } })) . splice () . into () , input : Box :: new (orig_node) , } } # [doc = " Count the cardinality of each input and periodically output to a file"] pub fn profiling < 'a > (ir : Vec < HfPlusLeaf < 'a > > , context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > ,) -> Vec < HfPlusLeaf < 'a > > { let mut id = 0 ; let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | { add_profiling_node (node , context , counters , counter_queue , & mut id , seen_tees) } , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn profiler_wrapping_all_operators () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let runtime_context = flow . runtime_context () ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (& built . ir ()) ; let counters = RuntimeData :: new ("Fake") ; let counter_queue = RuntimeData :: new ("Fake") ; let pushed_down = built . with_default_optimize () . optimize_with (| ir | super :: profiling (ir , runtime_context , counters , counter_queue)) ; insta :: assert_debug_snapshot ! (& pushed_down . ir ()) ; let _ = pushed_down . compile_no_network :: < MultiGraph > () ; } } } pub mod properties { pub use std :: collections :: HashSet ; pub use stageleft :: * ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , SeenTees } ; pub use crate :: properties :: PropertyDatabase ; # [doc = " Allows us to convert the hydroflow datatype for folds to a binary operation for the algebra"] # [doc = " property tests."] # [allow (dead_code)] pub fn convert_hf_to_binary < I , A : Default , F : Fn (& mut A , I) > (f : F) -> impl Fn (I , I) -> A { move | a , b | { let mut acc = Default :: default () ; f (& mut acc , a) ; f (& mut acc , b) ; acc } } # [cfg (stageleft_macro)] impl PropertyDatabase { # [doc = " Tags the expression as commutative."] pub fn add_commutative_tag < 'a , I , A , F : Fn (& mut A , I) , Q : Quoted < 'a , F > + Clone > (& mut self , expr : Q ,) -> Q { let expr_clone = expr . clone () ; self . commutative . insert (expr_clone . splice ()) ; expr } pub fn is_tagged_commutative (& self , expr : & syn :: Expr) -> bool { self . commutative . contains (expr) } } pub fn properties_optimize_node < 'a > (node : & mut HfPlusNode < 'a > , db : & PropertyDatabase , seen_tees : & mut SeenTees < 'a > ,) { node . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , seen_tees ,) ; match node { HfPlusNode :: ReduceKeyed { f , .. } if db . is_tagged_commutative (& f . 0) => { dbg ! ("IDENTIFIED COMMUTATIVE OPTIMIZATION for {:?}" , & f) ; } _ => { } } } pub fn properties_optimize < 'a > (ir : Vec < HfPlusLeaf < 'a > > , db : & PropertyDatabase ,) -> Vec < HfPlusLeaf < 'a > > { let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use super :: * ; use crate :: deploy :: SingleProcessGraph ; use crate :: FlowBuilder ; # [test] fn test_property_database () { let mut db = PropertyDatabase :: default () ; assert ! (! db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; let _ = db . add_commutative_tag (q ! (| a : & mut i32 , b : i32 | * a += b)) ; assert ! (db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; } # [test] fn test_property_optimized () { let flow = FlowBuilder :: new () ; let mut database = PropertyDatabase :: default () ; let process = flow . process :: < () > () ; let counter_func = q ! (| count : & mut i32 , _ | * count += 1) ; let _ = database . add_commutative_tag (counter_func) ; flow . source_iter (& process , q ! (vec ! [])) . map (q ! (| string : String | (string , ()))) . tick_batch () . fold_keyed (q ! (|| 0) , counter_func) . all_ticks () . for_each (q ! (| (string , count) | println ! ("{}: {}" , string , count))) ; let built = flow . finalize () . optimize_with (| ir | properties_optimize (ir , & database)) . with_default_optimize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let _ = built . compile_no_network :: < SingleProcessGraph > () ; } } } pub use crate :: RuntimeContext ; # [cfg (stageleft_macro)] impl Copy for RuntimeContext < '_ > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Context > for RuntimeContext < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (quote ! (& context))) } } pub use crate :: HfCompiled ; # [cfg (stageleft_macro)] impl < 'a , ID > HfCompiled < 'a , ID > { pub fn hydroflow_ir (& self) -> & BTreeMap < usize , HydroflowGraph > { & self . hydroflow_ir } } # [cfg (stageleft_macro)] impl < 'a > HfCompiled < 'a , usize > { pub fn with_dynamic_id (self , id : impl Quoted < 'a , usize >) -> HfBuiltWithId < 'a > { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; let mut conditioned_tokens = None ; for (subgraph_id , flat_graph) in self . hydroflow_ir { let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; let my_extra_stmts = self . extra_stmts . get (& subgraph_id) . cloned () . unwrap_or_default () ; if let Some (conditioned_tokens) = conditioned_tokens . as_mut () { * conditioned_tokens = syn :: parse_quote ! { # conditioned_tokens else if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } } ; } else { conditioned_tokens = Some (syn :: parse_quote ! { if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } }) ; } } let conditioned_tokens : TokenStream = conditioned_tokens . unwrap () ; let id = id . splice () ; HfBuiltWithId { tokens : syn :: parse_quote ! ({ let __given_id = # id ; # conditioned_tokens else { panic ! ("Invalid node id: {}" , __given_id) ; } }) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfCompiled < 'a , () > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfCompiled < 'a , () > { fn to_tokens (mut self) -> (Option < TokenStream > , Option < TokenStream >) { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; if self . hydroflow_ir . len () != 1 { panic ! ("Expected exactly one subgraph in the Hydroflow IR") ; } let flat_graph = self . hydroflow_ir . remove (& 0) . unwrap () ; let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; (None , Some (tokens)) } } pub use crate :: HfBuiltWithId ; # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfBuiltWithId < 'a > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfBuiltWithId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (self . tokens)) } }
[INFO] [stdout]   |
[INFO] [stdout] help: ...otherwise replace it with an invocation of macro `deref`
[INFO] [stdout]   |
[INFO] [stdout] 1 - pub use std :: collections :: BTreeMap ; pub use std :: marker :: PhantomData ; pub use hydroflow :: scheduled :: context :: Context ; pub use hydroflow :: scheduled :: graph :: Hydroflow ; pub use hydroflow :: * ; pub use lang :: graph :: { partition_graph , HydroflowGraph } ; pub use proc_macro2 :: TokenStream ; pub use quote :: quote ; pub use stageleft :: runtime_support :: FreeVariable ; pub use stageleft :: Quoted ; pub mod runtime_support { pub use bincode ; } pub mod stream { pub use std :: cell :: RefCell ; pub use std :: hash :: Hash ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow :: bytes :: Bytes ; pub use hydroflow :: futures :: Sink ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: quote ; pub use serde :: de :: DeserializeOwned ; pub use serde :: Serialize ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use syn :: parse_quote ; pub use crate :: builder :: { ClusterIds , FlowLeaves } ; pub use crate :: cycle :: { CycleCollection , CycleComplete } ; pub use crate :: ir :: { DebugInstantiate , HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { CanSend , Location , LocationId } ; pub use crate :: { Cluster , Optional , Singleton } ; pub use crate :: stream :: Unbounded ; pub use crate :: stream :: Bounded ; pub use crate :: stream :: NoTick ; pub use crate :: stream :: Tick ; pub use crate :: stream :: Stream ; # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Stream { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Stream < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Stream { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , C , N > > ,) -> Stream < 'a , (T , O) , W , C , N > where O : Clone , { let other : Optional < 'a , O , Bounded , C , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn cross_product < O > (self , other : Stream < 'a , O , W , C , N >) -> Stream < 'a , (T , O) , W , C , N > where T : Clone , O : Clone , { if self . location_kind != other . location_kind { panic ! ("cross_product must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossProduct (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn union (self , other : Stream < 'a , T , W , C , N >) -> Stream < 'a , T , W , C , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn dest_sink < S : Unpin + Sink < T > + 'a > (self , sink : impl Quoted < 'a , S >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: DestSink { sink : sink . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn first (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } # [doc = " Allow this stream through if the other stream has elements, otherwise the output is empty."] pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } # [doc = " Allow this stream through if the other stream is empty, otherwise the output is empty."] pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn enumerate (self) -> Stream < 'a , (usize , T) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Enumerate (Box :: new (self . ir_node . into_inner ())) ,) } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn sort (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Ord , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Sort (Box :: new (self . ir_node . into_inner ())) ,) } pub fn count (self) -> Singleton < 'a , usize , Bounded , Tick , N > { self . fold (q ! (|| 0usize) , q ! (| count , _ | * count += 1)) } pub fn delta (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } pub fn unique (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Eq + Hash , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unique (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn tick_batch (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_prefix (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { self . tick_batch () . persist () } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn for_each < F : Fn (T) + 'a > (self , f : impl IntoQuotedMut < 'a , F >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: ForEach { input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , f : f . splice () . into () , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Unbounded , NoTick , N > { pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . tick_batch () . continue_if (samples . first ()) . all_ticks () } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Unbounded , NoTick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , C , N : Location > Stream < 'a , T , Bounded , C , N > { pub fn filter_not_in (self , other : Stream < 'a , T , Bounded , C , N >) -> Stream < 'a , T , Bounded , C , N > where T : Eq + Hash , { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Difference (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Stream < 'a , & T , W , C , N > { pub fn cloned (self) -> Stream < 'a , T , W , C , N > { self . map (q ! (| d | d . clone ())) } } # [cfg (stageleft_macro)] impl < 'a , K , V1 , W , C , N : Location > Stream < 'a , (K , V1) , W , C , N > { pub fn join < W2 , V2 > (self , n : Stream < 'a , (K , V2) , W2 , C , N > ,) -> Stream < 'a , (K , (V1 , V2)) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Join (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } pub fn anti_join < W2 > (self , n : Stream < 'a , K , W2 , C , N >) -> Stream < 'a , (K , V1) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("anti_join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: AntiJoin (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , K : Eq + Hash , V , N : Location > Stream < 'a , (K , V) , Bounded , Tick , N > { pub fn fold_keyed < A , I : Fn () -> A + 'a , F : Fn (& mut A , V) + 'a > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , A) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FoldKeyed { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce_keyed < F : Fn (& mut V , V) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , V) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: ReduceKeyed { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } pub fn get_this_crate () -> TokenStream { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , Span :: call_site ()) ; quote ! { # ident } } } } pub fn serialize_bincode < T : Serialize > (is_demux : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if is_demux { parse_quote ! { map (| (id , data) | { (id , # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into ()) }) } } else { parse_quote ! { map (| data | { # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into () }) } } } pub fn deserialize_bincode < T : DeserializeOwned > (tagged : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if tagged { parse_quote ! { map (| res | { let (id , b) = res . unwrap () ; (id , # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& b) . unwrap ()) }) } } else { parse_quote ! { map (| res | { # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& res . unwrap ()) . unwrap () }) } } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn send_bincode < N2 : Location , CoreType > (self , other : & N2 ,) -> Stream < 'a , N :: Out < CoreType > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T > , CoreType : Serialize + DeserializeOwned , { let serialize_pipeline = Some (serialize_bincode :: < CoreType > (N :: is_demux ())) ; let deserialize_pipeline = Some (deserialize_bincode :: < CoreType > (N :: is_tagged ())) ; Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bytes < N2 : Location > (self , other : & N2 ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T > , { Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline : None , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline : if N :: is_tagged () { Some (parse_quote ! (map (| (id , b) | (id , b . unwrap () . freeze ())))) } else { Some (parse_quote ! (map (| b | b . unwrap () . freeze ()))) } , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bincode_interleaved < N2 : Location , Tag , CoreType > (self , other : & N2 ,) -> Stream < 'a , CoreType , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T , Out < CoreType > = (Tag , CoreType) > , CoreType : Serialize + DeserializeOwned , { self . send_bincode :: < N2 , CoreType > (other) . map (q ! (| (_ , b) | b)) } pub fn send_bytes_interleaved < N2 : Location , Tag > (self , other : & N2 ,) -> Stream < 'a , Bytes , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T , Out < Bytes > = (Tag , Bytes) > , { self . send_bytes :: < N2 > (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bincode < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < T > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) > , T : Clone + Serialize + DeserializeOwned , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bincode (other) } pub fn broadcast_bincode_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , T , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) , Out < T > = (Tag , T) > + 'a , T : Clone + Serialize + DeserializeOwned , { self . broadcast_bincode (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bytes < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) > + 'a , T : Clone , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bytes (other) } pub fn broadcast_bytes_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , Bytes , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) , Out < Bytes > = (Tag , Bytes) > + 'a , T : Clone , { self . broadcast_bytes (other) . map (q ! (| (_ , b) | b)) } } } pub use stream :: { Bounded , NoTick , Stream , Tick , Unbounded } ; pub mod singleton { pub use std :: cell :: RefCell ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use crate :: builder :: FlowLeaves ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial , CycleComplete } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: Stream ; pub use crate :: singleton :: CrossResult ; # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Singleton < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Singleton :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } pub use crate :: singleton :: Singleton ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Singleton { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleComplete < 'a > for Singleton < 'a , T , Bounded , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleCollectionWithInitial < 'a > for Singleton < 'a , T , Bounded , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , initial : Self , l : LocationId ,) -> Self { Singleton :: new (l , ir_leaves , HfPlusNode :: Union (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , }) , initial . ir_node . into_inner () . into () ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Singleton < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Singleton { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , U , W , C , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (Self :: other_ir_node (other)) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Singleton < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CrossSingleton (Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , Box :: new (HfPlusNode :: Unpersist (Box :: new (Self :: other_ir_node (other)))) ,))) ,) } } pub use crate :: singleton :: Optional ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Optional { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } pub fn some (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: new (singleton . location_kind , singleton . ir_leaves , singleton . ir_node . into_inner () ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > From < Singleton < 'a , T , W , C , N > > for Optional < 'a , T , W , C , N > { fn from (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: some (singleton) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Optional < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Optional { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn into_stream (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , Tick , N > > ,) -> Optional < 'a , (T , O) , Bounded , Tick , N > where O : Clone , { let other : Optional < 'a , O , Bounded , Tick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn union (self , other : Optional < 'a , T , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Optional < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_samples (self) -> Stream < 'a , T , Unbounded , NoTick , N > { self . latest_tick () . all_ticks () } pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . latest_tick () . continue_if (samples . first ()) . latest () . tick_samples () } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Unbounded , NoTick , N > > ,) -> Optional < 'a , (T , O) , Unbounded , NoTick , N > where O : Clone , { let other : Optional < 'a , O , Unbounded , NoTick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } self . latest_tick () . cross_singleton (other . latest_tick ()) . latest () } } } pub use singleton :: { Optional , Singleton } ; pub mod location { pub use std :: marker :: PhantomData ; pub use crate :: location :: LocationId ; pub use crate :: location :: Location ; pub use crate :: location :: Process ; # [cfg (stageleft_macro)] impl < P > Clone for Process < P > { fn clone (& self) -> Self { Process { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < P > Location for Process < P > { fn id (& self) -> LocationId { LocationId :: Process (self . id) } } pub use crate :: location :: Cluster ; # [cfg (stageleft_macro)] impl < C > Clone for Cluster < C > { fn clone (& self) -> Self { Cluster { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < C > Location for Cluster < C > { fn id (& self) -> LocationId { LocationId :: Cluster (self . id) } } pub use crate :: location :: CanSend ; # [cfg (stageleft_macro)] impl < P1 , P2 > CanSend < Process < P2 > > for Process < P1 > { type In < T > = T ; type Out < T > = T ; fn is_demux () -> bool { false } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < P1 , C2 > CanSend < Cluster < C2 > > for Process < P1 > { type In < T > = (u32 , T) ; type Out < T > = T ; fn is_demux () -> bool { true } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < C1 , P2 > CanSend < Process < P2 > > for Cluster < C1 > { type In < T > = T ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { false } fn is_tagged () -> bool { true } } # [cfg (stageleft_macro)] impl < C1 , C2 > CanSend < Cluster < C2 > > for Cluster < C1 > { type In < T > = (u32 , T) ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { true } fn is_tagged () -> bool { true } } } pub use location :: { Cluster , Process } ; pub mod deploy { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use stageleft :: Quoted ; pub mod graphs { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use super :: { LocalDeploy , Node , ProcessSpec } ; pub use crate :: deploy :: graphs :: SingleProcessGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for SingleProcessGraph { type Process = SingleNode ; type Cluster = SingleNode ; type Meta = () ; type GraphId = () ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { SingleNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { SingleNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , SingleProcessGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> SingleNode { SingleNode { } } } pub use crate :: deploy :: graphs :: SingleNode ; # [cfg (stageleft_macro)] impl Node for SingleNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } pub use crate :: deploy :: graphs :: MultiGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for MultiGraph { type Process = MultiNode ; type Cluster = MultiNode ; type Meta = () ; type GraphId = usize ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { MultiNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { MultiNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , MultiGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> MultiNode { MultiNode { } } } pub use crate :: deploy :: graphs :: MultiNode ; # [cfg (stageleft_macro)] impl Node for MultiNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } } pub use graphs :: * ; pub use crate :: deploy :: LocalDeploy ; pub use crate :: deploy :: Deploy ; # [cfg (stageleft_macro)] impl < 'a , T : Deploy < 'a , Process = N , Cluster = C , Meta = M , GraphId = R > , N : Node < Meta = M > , C : Node < Meta = M > , M : Default , R , > LocalDeploy < 'a > for T { type Process = N ; type Cluster = C ; type Meta = M ; type GraphId = R ; fn has_trivial_node () -> bool { < T as Deploy < 'a > > :: has_trivial_node () } fn trivial_process (id : usize) -> Self :: Process { < T as Deploy < 'a > > :: trivial_process (id) } fn trivial_cluster (id : usize) -> Self :: Cluster { < T as Deploy < 'a > > :: trivail_cluster (id) } } pub use crate :: deploy :: ProcessSpec ; pub use crate :: deploy :: ClusterSpec ; pub use crate :: deploy :: Node ; } pub use deploy :: { ClusterSpec , Deploy , ProcessSpec } ; pub mod cycle { pub use std :: marker :: PhantomData ; pub use crate :: builder :: FlowLeaves ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: cycle :: CycleComplete ; pub use crate :: cycle :: CycleCollection ; pub use crate :: cycle :: CycleCollectionWithInitial ; pub use crate :: cycle :: HfCycle ; # [cfg (stageleft_macro)] impl < 'a , S : CycleComplete < 'a > > HfCycle < 'a , S > { pub fn complete (self , stream : S) { let ident = self . ident ; S :: complete (stream , ident) } } } pub use cycle :: HfCycle ; pub mod builder { pub use std :: cell :: RefCell ; pub use std :: collections :: HashMap ; pub use std :: marker :: PhantomData ; pub use std :: rc :: Rc ; pub use std :: time :: Duration ; pub use hydroflow :: futures :: stream :: Stream as FuturesStream ; pub use hydroflow :: { tokio , tokio_stream } ; pub use internal :: TokenStream ; pub use proc_macro2 :: Span ; pub use quote :: quote ; pub use runtime_support :: FreeVariable ; pub use stageleft :: * ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Cluster , Location , LocationId , Process } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: { HfCycle , Optional , RuntimeContext , Singleton , Stream } ; pub mod built { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use hydroflow_lang :: graph :: { eliminate_extra_unions_tees , HydroflowGraph } ; pub use super :: deploy :: { DeployFlow , DeployResult } ; pub use crate :: deploy :: { ClusterSpec , Deploy , LocalDeploy , ProcessSpec } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Cluster , Process } ; pub use crate :: HfCompiled ; pub use crate :: builder :: built :: BuiltFlow ; # [cfg (stageleft_macro)] impl < 'a > Drop for BuiltFlow < 'a > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped BuiltFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn ir (& self) -> & Vec < HfPlusLeaf < 'a > > { & self . ir } pub fn optimize_with (mut self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> BuiltFlow < 'a > { self . used = true ; BuiltFlow { ir : f (std :: mem :: take (& mut self . ir)) , processes : std :: mem :: take (& mut self . processes) , clusters : std :: mem :: take (& mut self . clusters) , used : false , _phantom : PhantomData , } } } pub fn build_inner (ir : & mut Vec < HfPlusLeaf >) -> BTreeMap < usize , HydroflowGraph > { let mut builders = BTreeMap :: new () ; let mut built_tees = HashMap :: new () ; let mut next_stmt_id = 0 ; for leaf in ir { leaf . emit (& mut builders , & mut built_tees , & mut next_stmt_id) ; } builders . into_iter () . map (| (k , v) | { let (mut flat_graph , _ , _) = v . build () ; eliminate_extra_unions_tees (& mut flat_graph) ; (k , flat_graph) }) . collect () } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn compile_no_network < D : LocalDeploy < 'a > > (mut self) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; HfCompiled { hydroflow_ir : build_inner (& mut self . ir) , extra_stmts : BTreeMap :: new () , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> BuiltFlow < 'a > { self . optimize_with (crate :: persist_pullup :: persist_pullup) } fn into_deploy < D : LocalDeploy < 'a > > (mut self) -> DeployFlow < 'a , D > { self . used = true ; let processes = if D :: has_trivial_node () { self . processes . iter () . map (| id | (* id , D :: trivial_process (* id))) . collect () } else { HashMap :: new () } ; let clusters = if D :: has_trivial_node () { self . clusters . iter () . map (| id | (* id , D :: trivial_cluster (* id))) . collect () } else { HashMap :: new () } ; DeployFlow { ir : std :: mem :: take (& mut self . ir) , nodes : processes , clusters , used : false , _phantom : PhantomData , } } pub fn with_process < P , D : LocalDeploy < 'a > > (self , process : & Process < P > , spec : impl ProcessSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_process (process , spec) } pub fn with_cluster < C , D : LocalDeploy < 'a > > (self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_cluster (cluster , spec) } pub fn compile < D : Deploy < 'a > + 'a > (self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . into_deploy :: < D > () . compile (env) } pub fn deploy < D : Deploy < 'a , CompileEnv = () > + 'a > (self , env : & mut D :: InstantiateEnv ,) -> DeployResult < 'a , D > { self . into_deploy :: < D > () . deploy (env) } } } pub mod deploy { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use proc_macro2 :: Span ; pub use stageleft :: Quoted ; pub use super :: built :: build_inner ; pub use crate :: deploy :: { LocalDeploy , Node } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: { Cluster , ClusterSpec , Deploy , HfCompiled , Process , ProcessSpec } ; pub use crate :: builder :: deploy :: DeployFlow ; # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > Drop for DeployFlow < 'a , D > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped DeployFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > DeployFlow < 'a , D > { pub fn with_process < P > (mut self , process : & Process < P > , spec : impl ProcessSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < P > () . to_string () ; self . nodes . insert (process . id , spec . build (process . id , & tag_name)) ; self } pub fn with_cluster < C > (mut self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < C > () . to_string () ; self . clusters . insert (cluster . id , spec . build (cluster . id , & tag_name)) ; self } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployFlow < 'a , D > { pub fn compile (mut self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; let mut seen_tees : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | leaf . compile_network :: < D > (env , & mut seen_tees , & self . nodes , & self . clusters)) . collect () ; let extra_stmts = self . extra_stmts (env) ; HfCompiled { hydroflow_ir : build_inner (& mut ir_leaves_networked) , extra_stmts , _phantom : PhantomData , } } fn extra_stmts (& self , env : & < D as Deploy < 'a > > :: CompileEnv) -> BTreeMap < usize , Vec < syn :: Stmt > > { let all_locations_count = self . nodes . len () + self . clusters . len () ; let mut extra_stmts : BTreeMap < usize , Vec < syn :: Stmt > > = BTreeMap :: new () ; for & c_id in self . clusters . keys () { let self_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , c_id) , Span :: call_site () ,) ; let self_id_expr = D :: cluster_self_id (env) . splice () ; extra_stmts . entry (c_id) . or_default () . push (syn :: parse_quote ! { let # self_id_ident = # self_id_expr ; }) ; for other_location in 0 .. all_locations_count { let other_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , c_id) , Span :: call_site () ,) ; let other_id_expr = D :: cluster_ids (env , c_id) . splice () ; extra_stmts . entry (other_location) . or_default () . push (syn :: parse_quote ! { let # other_id_ident = # other_id_expr ; }) ; } } extra_stmts } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a , CompileEnv = () > > DeployFlow < 'a , D > { # [must_use] pub fn deploy (mut self , env : & mut D :: InstantiateEnv) -> DeployResult < 'a , D > { self . used = true ; let mut seen_tees_instantiate : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | { leaf . compile_network :: < D > (& () , & mut seen_tees_instantiate , & self . nodes , & self . clusters ,) }) . collect () ; let mut compiled = build_inner (& mut ir_leaves_networked) ; let mut extra_stmts = self . extra_stmts (& ()) ; let mut meta = D :: Meta :: default () ; let (mut processes , mut clusters) = (std :: mem :: take (& mut self . nodes) . into_iter () . map (| (node_id , node) | { node . instantiate (env , & mut meta , compiled . remove (& node_id) . unwrap () , extra_stmts . remove (& node_id) . unwrap_or_default () ,) ; (node_id , node) }) . collect :: < HashMap < _ , _ > > () , std :: mem :: take (& mut self . clusters) . into_iter () . map (| (cluster_id , cluster) | { cluster . instantiate (env , & mut meta , compiled . remove (& cluster_id) . unwrap () , extra_stmts . remove (& cluster_id) . unwrap_or_default () ,) ; (cluster_id , cluster) }) . collect :: < HashMap < _ , _ > > () ,) ; for node in processes . values_mut () { node . update_meta (& meta) ; } for cluster in clusters . values_mut () { cluster . update_meta (& meta) ; } let mut seen_tees_connect = HashMap :: new () ; for leaf in ir_leaves_networked { leaf . connect_network (& mut seen_tees_connect) ; } DeployResult { processes , clusters , } } } pub use crate :: builder :: deploy :: DeployResult ; # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployResult < 'a , D > { pub fn get_process < P > (& self , p : & Process < P >) -> & D :: Process { let id = match p . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . processes . get (& id) . unwrap () } pub fn get_cluster < C > (& self , c : & Cluster < C >) -> & D :: Cluster { let id = match c . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . clusters . get (& id) . unwrap () } } } # [doc = " Tracks the leaves of the dataflow IR. This is referenced by"] # [doc = " `Stream` and `HfCycle` to build the IR. The inner option will"] # [doc = " be set to `None` when this builder is finalized."] pub type FlowLeaves < 'a > = Rc < RefCell < Option < Vec < HfPlusLeaf < 'a > > > > > ; pub use crate :: builder :: ClusterIds ; # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Vec < u32 > > for ClusterIds < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , & 'a Vec < u32 > > for ClusterIds < 'a > { } # [derive (Copy , Clone)] pub struct ClusterSelfId < 'a > { pub id : usize , pub _phantom : PhantomData < & 'a mut & 'a u32 > , } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < u32 > for ClusterSelfId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , u32 > for ClusterSelfId < 'a > { } pub use crate :: builder :: FlowBuilder ; # [cfg (stageleft_macro)] impl < 'a > Drop for FlowBuilder < 'a > { fn drop (& mut self) { if ! self . finalized { panic ! ("Dropped FlowBuilder without finalizing, you may have forgotten to call `with_default_optimize`, `optimize_with`, or `finalize`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > QuotedContext for FlowBuilder < 'a > { fn create () -> Self { FlowBuilder :: new () } } # [cfg (stageleft_macro)] impl < 'a > FlowBuilder < 'a > { # [allow (clippy :: new_without_default)] pub fn new () -> FlowBuilder < 'a > { FlowBuilder { ir_leaves : Rc :: new (RefCell :: new (Some (Vec :: new ()))) , nodes : RefCell :: new (vec ! []) , clusters : RefCell :: new (vec ! []) , cycle_ids : RefCell :: new (HashMap :: new ()) , next_node_id : RefCell :: new (0) , finalized : false , _phantom : PhantomData , } } pub fn finalize (mut self) -> built :: BuiltFlow < 'a > { self . finalized = true ; built :: BuiltFlow { ir : self . ir_leaves . borrow_mut () . take () . unwrap () , processes : self . nodes . replace (vec ! []) , clusters : self . clusters . replace (vec ! []) , used : false , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> built :: BuiltFlow < 'a > { self . finalize () . with_default_optimize () } pub fn optimize_with (self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> built :: BuiltFlow < 'a > { self . finalize () . optimize_with (f) } pub fn ir_leaves (& self) -> & FlowLeaves < 'a > { & self . ir_leaves } pub fn process < P > (& self) -> Process < P > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . nodes . borrow_mut () . push (id) ; Process { id , _phantom : PhantomData , } } pub fn cluster < C > (& self) -> Cluster < C > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . clusters . borrow_mut () . push (id) ; Cluster { id , _phantom : PhantomData , } } pub fn runtime_context (& self) -> RuntimeContext < 'a > { RuntimeContext { _phantom : PhantomData , } } pub fn cluster_members < C > (& self , cluster : & Cluster < C > ,) -> impl Quoted < 'a , & 'a Vec < u32 > > + Copy + 'a { ClusterIds { id : cluster . id , _phantom : PhantomData , } } pub fn cluster_self_id < C > (& self , cluster : & Cluster < C >) -> impl Quoted < 'a , u32 > + Copy + 'a { ClusterSelfId { id : cluster . id , _phantom : PhantomData , } } pub fn spin < L : Location > (& self , on : & L) -> Stream < 'a , () , Unbounded , NoTick , L > { Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Spin () , location_kind : on . id () , })) ,) } pub fn spin_batch < L : Location > (& self , on : & L , batch_size : impl Quoted < 'a , usize > + Copy + 'a ,) -> Stream < 'a , () , Bounded , Tick , L > { self . spin (on) . flat_map (q ! (move | _ | 0 .. batch_size)) . map (q ! (| _ | ())) . tick_batch () } pub fn source_stream < T , E : FuturesStream < Item = T > + Unpin , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Unbounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Stream (e . into ()) , location_kind : on . id () , })) ,) } pub fn source_iter < T , E : IntoIterator < Item = T > , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Bounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , })) ,) } pub fn singleton < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Singleton < 'a , T , Bounded , NoTick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Singleton :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,)))) ,) } pub fn singleton_first_tick < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Optional < 'a , T , Bounded , Tick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,) } pub fn source_interval < L : Location > (& self , on : & L , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , () , Unbounded , NoTick , L > { let interval = interval . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : on . id () , })) ,) } pub fn source_interval_delayed < L : Location > (& self , on : & L , delay : impl Quoted < 'a , Duration > + Copy + 'a , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , tokio :: time :: Instant , Unbounded , NoTick , L > { self . source_stream (on , q ! (tokio_stream :: wrappers :: IntervalStream :: new (tokio :: time :: interval_at (tokio :: time :: Instant :: now () + delay , interval))) ,) . tick_batch () . first () . latest () } pub fn cycle < S : CycleCollection < 'a > > (& self , on : & S :: Location) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , on . id ()) ,) } pub fn cycle_with_initial < S : CycleCollectionWithInitial < 'a > > (& self , on : & S :: Location , initial : S ,) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , initial , on . id ()) ,) } } } pub use builder :: FlowBuilder ; pub mod ir { pub use core :: panic ; pub use std :: cell :: RefCell ; pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow_lang :: graph :: FlatGraphBuilder ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: ToTokens ; pub use syn :: parse_quote ; pub use crate :: deploy :: Deploy ; pub use crate :: location :: LocationId ; pub use crate :: ir :: DebugExpr ; # [cfg (stageleft_macro)] impl From < syn :: Expr > for DebugExpr { fn from (expr : syn :: Expr) -> DebugExpr { DebugExpr (expr) } } # [cfg (stageleft_macro)] impl Deref for DebugExpr { type Target = syn :: Expr ; fn deref (& self) -> & Self :: Target { & self . 0 } } # [cfg (stageleft_macro)] impl ToTokens for DebugExpr { fn to_tokens (& self , tokens : & mut TokenStream) { self . 0 . to_tokens (tokens) ; } } # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugExpr { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "{}" , self . 0 . to_token_stream ()) } } pub use crate :: ir :: DebugInstantiate ; # [cfg (stageleft_macro)] impl < 'a > std :: fmt :: Debug for DebugInstantiate < 'a > { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<network instantiate>") } } pub use crate :: ir :: DebugPipelineFn ; # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugPipelineFn { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<function>") } } pub use crate :: ir :: HfPlusSource ; pub use crate :: ir :: HfPlusLeaf ; # [cfg (stageleft_macro)] impl < 'a > HfPlusLeaf < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . compile_network :: < D > (compile_env , s , nodes , clusters) ; } , seen_tees ,) } pub fn connect_network (self , seen_tees : & mut SeenTees < 'a >) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . connect_network (s) ; } , seen_tees ,) } pub fn transform_children (self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) -> HfPlusLeaf < 'a > { match self { HfPlusLeaf :: ForEach { f , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: ForEach { f , input } } HfPlusLeaf :: DestSink { sink , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: DestSink { sink , input } } HfPlusLeaf :: CycleSink { ident , location_kind , mut input , } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: CycleSink { ident , location_kind , input , } } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) { match self { HfPlusLeaf :: ForEach { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> for_each (# f) ; }) ; } HfPlusLeaf :: DestSink { sink , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink) ; }) ; } HfPlusLeaf :: CycleSink { ident , location_kind , input , } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; assert_eq ! (input_location_id , * location_id , "cycle_sink location mismatch") ; graph_builders . entry (* location_id) . or_default () . add_statement (parse_quote ! { # ident = # input_ident ; }) ; } } } } pub use crate :: ir :: HfPlusNode ; pub type SeenTees < 'a > = HashMap < * const RefCell < HfPlusNode < 'a > > , Rc < RefCell < HfPlusNode < 'a > > > > ; # [cfg (stageleft_macro)] impl < 'a > HfPlusNode < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (& mut self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) { self . transform_children (| n , s | n . compile_network :: < D > (compile_env , s , nodes , clusters) , seen_tees ,) ; if let HfPlusNode :: Network { from_location , to_location , instantiate_fn , .. } = self { let (sink_expr , source_expr , connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { let ((sink , source) , connect_fn) = match (from_location , to_location) { (LocationId :: Process (from) , LocationId :: Process (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: o2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Process (from) , LocationId :: Cluster (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: o2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Process (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: m2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Cluster (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: m2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } } ; (sink , source , connect_fn) } DebugInstantiate :: Finalized (_ , _ , _) => panic ! ("network already finalized") , } ; * instantiate_fn = DebugInstantiate :: Finalized (sink_expr , source_expr , connect_fn) ; } } pub fn connect_network (& mut self , seen_tees : & mut SeenTees < 'a >) { self . transform_children (| n , s | n . connect_network (s) , seen_tees) ; if let HfPlusNode :: Network { instantiate_fn , .. } = self { match instantiate_fn { DebugInstantiate :: Building () => panic ! ("network not built") , DebugInstantiate :: Finalized (_ , _ , ref connect_fn) => { connect_fn () ; } } } } pub fn transform_children (& mut self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) { match self { HfPlusNode :: Placeholder => { panic ! () ; } HfPlusNode :: Source { .. } => { } HfPlusNode :: CycleSource { .. } => { } HfPlusNode :: Tee { inner } => { if let Some (transformed) = seen_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { * inner = transformed . clone () ; } else { let transformed_cell = Rc :: new (RefCell :: new (HfPlusNode :: Placeholder)) ; seen_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , transformed_cell . clone () ,) ; let mut orig = inner . replace (HfPlusNode :: Placeholder) ; transform (& mut orig , seen_tees) ; * transformed_cell . borrow_mut () = orig ; * inner = transformed_cell ; } } HfPlusNode :: Persist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Unpersist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Delta (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Union (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossProduct (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossSingleton (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Join (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Difference (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: AntiJoin (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Map { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FlatMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Filter { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FilterMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Sort (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: DeferTick (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Enumerate (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Inspect { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Unique (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Fold { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FoldKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Reduce { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: ReduceKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Network { input , .. } => { transform (input . as_mut () , seen_tees) ; } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) -> (syn :: Ident , usize) { match self { HfPlusNode :: Placeholder => { panic ! () } HfPlusNode :: Persist (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let persist_id = * next_stmt_id ; * next_stmt_id += 1 ; let persist_ident = syn :: Ident :: new (& format ! ("stream_{}" , persist_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # persist_ident = # inner_ident -> persist ::<'static > () ; }) ; (persist_ident , location) } HfPlusNode :: Unpersist (_) => { panic ! ("Unpersist is a marker node and should have been optimized away. This is likely a compiler bug.") } HfPlusNode :: Delta (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let delta_id = * next_stmt_id ; * next_stmt_id += 1 ; let delta_ident = syn :: Ident :: new (& format ! ("stream_{}" , delta_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # delta_ident = # inner_ident -> multiset_delta () ; }) ; (delta_ident , location) } HfPlusNode :: Source { source , location_kind , } => { let source_id = * next_stmt_id ; * next_stmt_id += 1 ; let source_ident = syn :: Ident :: new (& format ! ("stream_{}" , source_id) , Span :: call_site ()) ; let source_stmt = match source { HfPlusSource :: Stream (expr) => { parse_quote ! { # source_ident = source_stream (# expr) ; } } HfPlusSource :: Iter (expr) => { parse_quote ! { # source_ident = source_iter (# expr) ; } } HfPlusSource :: Interval (expr) => { parse_quote ! { # source_ident = source_interval (# expr) ; } } HfPlusSource :: Spin () => { parse_quote ! { # source_ident = spin () ; } } } ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; graph_builders . entry (* location_id) . or_default () . add_statement (source_stmt) ; (source_ident , * location_id) } HfPlusNode :: CycleSource { ident , location_kind , } => { let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; (ident . clone () , * location_id) } HfPlusNode :: Tee { inner } => { if let Some (ret) = built_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { ret . clone () } else { let (inner_ident , inner_location_id) = inner . borrow () . emit (graph_builders , built_tees , next_stmt_id) ; let tee_id = * next_stmt_id ; * next_stmt_id += 1 ; let tee_ident = syn :: Ident :: new (& format ! ("stream_{}" , tee_id) , Span :: call_site ()) ; let builder = graph_builders . entry (inner_location_id) . or_default () ; builder . add_statement (parse_quote ! { # tee_ident = # inner_ident -> tee () ; }) ; built_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , (tee_ident . clone () , inner_location_id) ,) ; (tee_ident , inner_location_id) } } HfPlusNode :: Union (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "union inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let union_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # union_ident = union () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [0] # union_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # union_ident ; }) ; (union_ident , left_location_id) } HfPlusNode :: CrossSingleton (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "cross_singleton inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let cross_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # cross_ident = cross_singleton () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [input] # cross_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [single] # cross_ident ; }) ; (cross_ident , left_location_id) } HfPlusNode :: CrossProduct (..) | HfPlusNode :: Join (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: CrossProduct (..)) { parse_quote ! (cross_join_multiset) } else { parse_quote ! (join_multiset) } ; let (HfPlusNode :: CrossProduct (left , right) | HfPlusNode :: Join (left , right)) = self else { unreachable ! () } ; let (left_inner , left_was_persist) = if let HfPlusNode :: Persist (left) = left . as_ref () { (left , true) } else { (left , false) } ; let (right_inner , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left_inner . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right_inner . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "join / cross product inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; match (left_was_persist , right_was_persist) { (true , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'static > () ; }) ; } (true , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'tick > () ; }) ; } (false , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } (false , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } } ; builder . add_statement (parse_quote ! { # left_ident -> [0] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Difference (..) | HfPlusNode :: AntiJoin (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Difference (..)) { parse_quote ! (difference_multiset) } else { parse_quote ! (anti_join_multiset) } ; let (HfPlusNode :: Difference (left , right) | HfPlusNode :: AntiJoin (left , right)) = self else { unreachable ! () } ; let (right , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "difference / anti join inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; if right_was_persist { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } else { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } builder . add_statement (parse_quote ! { # left_ident -> [pos] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [neg] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Map { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let map_id = * next_stmt_id ; * next_stmt_id += 1 ; let map_ident = syn :: Ident :: new (& format ! ("stream_{}" , map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # map_ident = # input_ident -> map (# f) ; }) ; (map_ident , input_location_id) } HfPlusNode :: FlatMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let flat_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let flat_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , flat_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # flat_map_ident = # input_ident -> flat_map (# f) ; }) ; (flat_map_ident , input_location_id) } HfPlusNode :: Filter { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_ident = # input_ident -> filter (# f) ; }) ; (filter_ident , input_location_id) } HfPlusNode :: FilterMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_map_ident = # input_ident -> filter_map (# f) ; }) ; (filter_map_ident , input_location_id) } HfPlusNode :: Sort (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sort_id = * next_stmt_id ; * next_stmt_id += 1 ; let sort_ident = syn :: Ident :: new (& format ! ("stream_{}" , sort_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # sort_ident = # input_ident -> sort () ; }) ; (sort_ident , input_location_id) } HfPlusNode :: DeferTick (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let defer_tick_id = * next_stmt_id ; * next_stmt_id += 1 ; let defer_tick_ident = syn :: Ident :: new (& format ! ("stream_{}" , defer_tick_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # defer_tick_ident = # input_ident -> defer_tick_lazy () ; }) ; (defer_tick_ident , input_location_id) } HfPlusNode :: Enumerate (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let enumerate_id = * next_stmt_id ; * next_stmt_id += 1 ; let enumerate_ident = syn :: Ident :: new (& format ! ("stream_{}" , enumerate_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # enumerate_ident = # input_ident -> enumerate () ; }) ; (enumerate_ident , input_location_id) } HfPlusNode :: Inspect { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let inspect_id = * next_stmt_id ; * next_stmt_id += 1 ; let inspect_ident = syn :: Ident :: new (& format ! ("stream_{}" , inspect_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # inspect_ident = # input_ident -> inspect (# f) ; }) ; (inspect_ident , input_location_id) } HfPlusNode :: Unique (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let unique_id = * next_stmt_id ; * next_stmt_id += 1 ; let unique_ident = syn :: Ident :: new (& format ! ("stream_{}" , unique_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # unique_ident = # input_ident -> unique ::<'tick > () ; }) ; (unique_ident , input_location_id) } HfPlusNode :: Fold { .. } | HfPlusNode :: FoldKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Fold { .. }) { parse_quote ! (fold) } else { parse_quote ! (fold_keyed) } ; let (HfPlusNode :: Fold { init , acc , input } | HfPlusNode :: FoldKeyed { init , acc , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let fold_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'static > (# init , # acc) ; }) ; } else { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'tick > (# init , # acc) ; }) ; } (fold_ident , input_location_id) } HfPlusNode :: Reduce { .. } | HfPlusNode :: ReduceKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Reduce { .. }) { parse_quote ! (reduce) } else { parse_quote ! (reduce_keyed) } ; let (HfPlusNode :: Reduce { f , input } | HfPlusNode :: ReduceKeyed { f , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let reduce_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'static > (# f) ; }) ; } else { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'tick > (# f) ; }) ; } (reduce_ident , input_location_id) } HfPlusNode :: Network { from_location : _ , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input , } => { let (sink_expr , source_expr , _connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { panic ! ("Expected the network to be finalized") } DebugInstantiate :: Finalized (sink , source , connect_fn) => { (sink , source , connect_fn) } } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sender_builder = graph_builders . entry (input_location_id) . or_default () ; if let Some (serialize_pipeline) = serialize_pipeline { sender_builder . add_statement (parse_quote ! { # input_ident -> # serialize_pipeline -> dest_sink (# sink_expr) ; }) ; } else { sender_builder . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink_expr) ; }) ; } let to_id = match to_location { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let receiver_builder = graph_builders . entry (* to_id) . or_default () ; let receiver_stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let receiver_stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , receiver_stream_id) , Span :: call_site ()) ; if let Some (deserialize_pipeline) = deserialize_pipeline { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) -> # deserialize_pipeline ; }) ; } else { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) ; }) ; } (receiver_stream_ident , * to_id) } } } } } pub mod persist_pullup { pub use std :: cell :: RefCell ; pub use std :: collections :: HashSet ; pub use std :: ops :: Deref ; pub use crate :: ir :: * ; pub fn persist_pullup_node < 'a > (node : & mut HfPlusNode < 'a > , seen_tees : & mut SeenTees < 'a > , persist_pulled_tees : & mut HashSet < * const RefCell < HfPlusNode < 'a > > > ,) { node . transform_children (| n , s | persist_pullup_node (n , s , persist_pulled_tees) , seen_tees ,) ; match node { HfPlusNode :: Unpersist (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Unpersist (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Delta (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Delta (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Tee { inner } => { if persist_pulled_tees . contains (& (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >)) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } else { let inner_borrow = inner . borrow () ; if let HfPlusNode :: Persist (_) = inner_borrow . deref () { drop (inner_borrow) ; persist_pulled_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >) ; if let HfPlusNode :: Persist (box behind_persist) = inner . replace (HfPlusNode :: Placeholder) { * inner . borrow_mut () = behind_persist ; } else { unreachable ! () } * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } } } HfPlusNode :: Map { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Map { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Map { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: FlatMap { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: FlatMap { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: FlatMap { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Filter { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Filter { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Filter { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Network { input : box HfPlusNode :: Persist (_) , .. } => { if let HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Union (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Union (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Union (left , right))) ; } else { unreachable ! () } } HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: CrossProduct (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,) ,)))) ; } else { unreachable ! () } } HfPlusNode :: Join (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Join (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: Join (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,))))) ; } else { unreachable ! () } } _ => { } } } pub fn persist_pullup (ir : Vec < HfPlusLeaf >) -> Vec < HfPlusLeaf > { let mut seen_tees = Default :: default () ; let mut persist_pulled_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| n , s | persist_pullup_node (n , s , & mut persist_pulled_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn persist_pullup_through_map () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } # [test] fn persist_pullup_behind_tee () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; let before_tee = flow . source_iter (& process , q ! (0 .. 10)) . tick_batch () . persist () ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } } } pub mod profiler { pub use std :: cell :: RefCell ; pub use hydroflow :: futures :: channel :: mpsc :: UnboundedSender ; pub use stageleft :: * ; pub use crate as hydroflow_plus ; pub use crate :: ir :: * ; pub use crate :: RuntimeContext ; pub fn increment_counter (count : & mut u64) { * count += 1 ; } pub fn quoted_any_fn < 'a , F : Fn (& usize) + 'a , Q : IntoQuotedMut < 'a , F > > (q : Q) -> Q { q } # [doc = " Add a profiling node before each node to count the cardinality of its input"] pub fn add_profiling_node < 'a > (node : & mut HfPlusNode < 'a > , _context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > , id : & mut u32 , seen_tees : & mut SeenTees < 'a > ,) { let my_id = * id ; * id += 1 ; node . transform_children (| node , seen_tees | { add_profiling_node (node , _context , counters , counter_queue , id , seen_tees) } , seen_tees ,) ; let orig_node = std :: mem :: replace (node , HfPlusNode :: Placeholder) ; * node = HfPlusNode :: Inspect { f : quoted_any_fn (q ! ({ counter_queue . borrow () . unbounded_send ((my_id as usize , counters . borrow () [my_id as usize])) . unwrap () ; counters . borrow_mut () [my_id as usize] = 0 ; move | _ | { hydroflow_plus :: profiler :: increment_counter (& mut counters . borrow_mut () [my_id as usize] ,) ; } })) . splice () . into () , input : Box :: new (orig_node) , } } # [doc = " Count the cardinality of each input and periodically output to a file"] pub fn profiling < 'a > (ir : Vec < HfPlusLeaf < 'a > > , context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > ,) -> Vec < HfPlusLeaf < 'a > > { let mut id = 0 ; let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | { add_profiling_node (node , context , counters , counter_queue , & mut id , seen_tees) } , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn profiler_wrapping_all_operators () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let runtime_context = flow . runtime_context () ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (& built . ir ()) ; let counters = RuntimeData :: new ("Fake") ; let counter_queue = RuntimeData :: new ("Fake") ; let pushed_down = built . with_default_optimize () . optimize_with (| ir | super :: profiling (ir , runtime_context , counters , counter_queue)) ; insta :: assert_debug_snapshot ! (& pushed_down . ir ()) ; let _ = pushed_down . compile_no_network :: < MultiGraph > () ; } } } pub mod properties { pub use std :: collections :: HashSet ; pub use stageleft :: * ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , SeenTees } ; pub use crate :: properties :: PropertyDatabase ; # [doc = " Allows us to convert the hydroflow datatype for folds to a binary operation for the algebra"] # [doc = " property tests."] # [allow (dead_code)] pub fn convert_hf_to_binary < I , A : Default , F : Fn (& mut A , I) > (f : F) -> impl Fn (I , I) -> A { move | a , b | { let mut acc = Default :: default () ; f (& mut acc , a) ; f (& mut acc , b) ; acc } } # [cfg (stageleft_macro)] impl PropertyDatabase { # [doc = " Tags the expression as commutative."] pub fn add_commutative_tag < 'a , I , A , F : Fn (& mut A , I) , Q : Quoted < 'a , F > + Clone > (& mut self , expr : Q ,) -> Q { let expr_clone = expr . clone () ; self . commutative . insert (expr_clone . splice ()) ; expr } pub fn is_tagged_commutative (& self , expr : & syn :: Expr) -> bool { self . commutative . contains (expr) } } pub fn properties_optimize_node < 'a > (node : & mut HfPlusNode < 'a > , db : & PropertyDatabase , seen_tees : & mut SeenTees < 'a > ,) { node . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , seen_tees ,) ; match node { HfPlusNode :: ReduceKeyed { f , .. } if db . is_tagged_commutative (& f . 0) => { dbg ! ("IDENTIFIED COMMUTATIVE OPTIMIZATION for {:?}" , & f) ; } _ => { } } } pub fn properties_optimize < 'a > (ir : Vec < HfPlusLeaf < 'a > > , db : & PropertyDatabase ,) -> Vec < HfPlusLeaf < 'a > > { let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use super :: * ; use crate :: deploy :: SingleProcessGraph ; use crate :: FlowBuilder ; # [test] fn test_property_database () { let mut db = PropertyDatabase :: default () ; assert ! (! db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; let _ = db . add_commutative_tag (q ! (| a : & mut i32 , b : i32 | * a += b)) ; assert ! (db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; } # [test] fn test_property_optimized () { let flow = FlowBuilder :: new () ; let mut database = PropertyDatabase :: default () ; let process = flow . process :: < () > () ; let counter_func = q ! (| count : & mut i32 , _ | * count += 1) ; let _ = database . add_commutative_tag (counter_func) ; flow . source_iter (& process , q ! (vec ! [])) . map (q ! (| string : String | (string , ()))) . tick_batch () . fold_keyed (q ! (|| 0) , counter_func) . all_ticks () . for_each (q ! (| (string , count) | println ! ("{}: {}" , string , count))) ; let built = flow . finalize () . optimize_with (| ir | properties_optimize (ir , & database)) . with_default_optimize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let _ = built . compile_no_network :: < SingleProcessGraph > () ; } } } pub use crate :: RuntimeContext ; # [cfg (stageleft_macro)] impl Copy for RuntimeContext < '_ > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Context > for RuntimeContext < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (quote ! (& context))) } } pub use crate :: HfCompiled ; # [cfg (stageleft_macro)] impl < 'a , ID > HfCompiled < 'a , ID > { pub fn hydroflow_ir (& self) -> & BTreeMap < usize , HydroflowGraph > { & self . hydroflow_ir } } # [cfg (stageleft_macro)] impl < 'a > HfCompiled < 'a , usize > { pub fn with_dynamic_id (self , id : impl Quoted < 'a , usize >) -> HfBuiltWithId < 'a > { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; let mut conditioned_tokens = None ; for (subgraph_id , flat_graph) in self . hydroflow_ir { let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; let my_extra_stmts = self . extra_stmts . get (& subgraph_id) . cloned () . unwrap_or_default () ; if let Some (conditioned_tokens) = conditioned_tokens . as_mut () { * conditioned_tokens = syn :: parse_quote ! { # conditioned_tokens else if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } } ; } else { conditioned_tokens = Some (syn :: parse_quote ! { if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } }) ; } } let conditioned_tokens : TokenStream = conditioned_tokens . unwrap () ; let id = id . splice () ; HfBuiltWithId { tokens : syn :: parse_quote ! ({ let __given_id = # id ; # conditioned_tokens else { panic ! ("Invalid node id: {}" , __given_id) ; } }) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfCompiled < 'a , () > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfCompiled < 'a , () > { fn to_tokens (mut self) -> (Option < TokenStream > , Option < TokenStream >) { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; if self . hydroflow_ir . len () != 1 { panic ! ("Expected exactly one subgraph in the Hydroflow IR") ; } let flat_graph = self . hydroflow_ir . remove (& 0) . unwrap () ; let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; (None , Some (tokens)) } } pub use crate :: HfBuiltWithId ; # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfBuiltWithId < 'a > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfBuiltWithId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (self . tokens)) } }
[INFO] [stdout] 1 + pub use std :: collections :: BTreeMap ; pub use std :: marker :: PhantomData ; pub use hydroflow :: scheduled :: context :: Context ; pub use hydroflow :: scheduled :: graph :: Hydroflow ; pub use hydroflow :: * ; pub use lang :: graph :: { partition_graph , HydroflowGraph } ; pub use proc_macro2 :: TokenStream ; pub use quote :: quote ; pub use stageleft :: runtime_support :: FreeVariable ; pub use stageleft :: Quoted ; pub mod runtime_support { pub use bincode ; } pub mod stream { pub use std :: cell :: RefCell ; pub use std :: hash :: Hash ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow :: bytes :: Bytes ; pub use hydroflow :: futures :: Sink ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: quote ; pub use serde :: de :: DeserializeOwned ; pub use serde :: Serialize ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use syn :: parse_quote ; pub use crate :: builder :: { ClusterIds , FlowLeaves } ; pub use crate :: cycle :: { CycleCollection , CycleComplete } ; pub use crate :: ir :: { DebugInstantiate , HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { CanSend , Location , LocationId } ; pub use crate :: { Cluster , Optional , Singleton } ; pub use crate :: stream :: Unbounded ; pub use crate :: stream :: Bounded ; pub use crate :: stream :: NoTick ; pub use crate :: stream :: Tick ; pub use crate :: stream :: Stream ; # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Stream { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Stream < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Stream { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , C , N > > ,) -> Stream < 'a , (T , O) , W , C , N > where O : Clone , { let other : Optional < 'a , O , Bounded , C , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn cross_product < O > (self , other : Stream < 'a , O , W , C , N >) -> Stream < 'a , (T , O) , W , C , N > where T : Clone , O : Clone , { if self . location_kind != other . location_kind { panic ! ("cross_product must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossProduct (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn union (self , other : Stream < 'a , T , W , C , N >) -> Stream < 'a , T , W , C , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn dest_sink < S : Unpin + Sink < T > + 'a > (self , sink : impl Quoted < 'a , S >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: DestSink { sink : sink . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn first (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } # [doc = " Allow this stream through if the other stream has elements, otherwise the output is empty."] pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } # [doc = " Allow this stream through if the other stream is empty, otherwise the output is empty."] pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn enumerate (self) -> Stream < 'a , (usize , T) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Enumerate (Box :: new (self . ir_node . into_inner ())) ,) } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn sort (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Ord , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Sort (Box :: new (self . ir_node . into_inner ())) ,) } pub fn count (self) -> Singleton < 'a , usize , Bounded , Tick , N > { self . fold (q ! (|| 0usize) , q ! (| count , _ | * count += 1)) } pub fn delta (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } pub fn unique (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Eq + Hash , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unique (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn tick_batch (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_prefix (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { self . tick_batch () . persist () } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn for_each < F : Fn (T) + 'a > (self , f : impl IntoQuotedMut < 'a , F >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: ForEach { input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , f : f . splice () . into () , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Unbounded , NoTick , N > { pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . tick_batch () . continue_if (samples . first ()) . all_ticks () } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Unbounded , NoTick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , C , N : Location > Stream < 'a , T , Bounded , C , N > { pub fn filter_not_in (self , other : Stream < 'a , T , Bounded , C , N >) -> Stream < 'a , T , Bounded , C , N > where T : Eq + Hash , { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Difference (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Stream < 'a , & T , W , C , N > { pub fn cloned (self) -> Stream < 'a , T , W , C , N > { self . map (q ! (| d | d . clone ())) } } # [cfg (stageleft_macro)] impl < 'a , K , V1 , W , C , N : Location > Stream < 'a , (K , V1) , W , C , N > { pub fn join < W2 , V2 > (self , n : Stream < 'a , (K , V2) , W2 , C , N > ,) -> Stream < 'a , (K , (V1 , V2)) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Join (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } pub fn anti_join < W2 > (self , n : Stream < 'a , K , W2 , C , N >) -> Stream < 'a , (K , V1) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("anti_join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: AntiJoin (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , K : Eq + Hash , V , N : Location > Stream < 'a , (K , V) , Bounded , Tick , N > { pub fn fold_keyed < A , I : Fn () -> A + 'a , F : Fn (& mut A , V) + 'a > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , A) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FoldKeyed { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce_keyed < F : Fn (& mut V , V) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , V) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: ReduceKeyed { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } pub fn get_this_crate () -> TokenStream { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , Span :: call_site ()) ; quote ! { # ident } } } } pub fn serialize_bincode < T : Serialize > (is_demux : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if is_demux { parse_quote ! { map (| (id , data) | { (id , # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into ()) }) } } else { parse_quote ! { map (| data | { # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into () }) } } } pub fn deserialize_bincode < T : DeserializeOwned > (tagged : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if tagged { parse_quote ! { map (| res | { let (id , b) = res . unwrap () ; (id , # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& b) . unwrap ()) }) } } else { parse_quote ! { map (| res | { # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& res . unwrap ()) . unwrap () }) } } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn send_bincode < N2 : Location , CoreType > (self , other : & N2 ,) -> Stream < 'a , N :: Out < CoreType > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T > , CoreType : Serialize + DeserializeOwned , { let serialize_pipeline = Some (serialize_bincode :: < CoreType > (N :: is_demux ())) ; let deserialize_pipeline = Some (deserialize_bincode :: < CoreType > (N :: is_tagged ())) ; Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bytes < N2 : Location > (self , other : & N2 ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T > , { Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline : None , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline : if N :: is_tagged () { Some (parse_quote ! (map (| (id , b) | (id , b . unwrap () . freeze ())))) } else { Some (parse_quote ! (map (| b | b . unwrap () . freeze ()))) } , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bincode_interleaved < N2 : Location , Tag , CoreType > (self , other : & N2 ,) -> Stream < 'a , CoreType , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T , Out < CoreType > = (Tag , CoreType) > , CoreType : Serialize + DeserializeOwned , { self . send_bincode :: < N2 , CoreType > (other) . map (q ! (| (_ , b) | b)) } pub fn send_bytes_interleaved < N2 : Location , Tag > (self , other : & N2 ,) -> Stream < 'a , Bytes , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T , Out < Bytes > = (Tag , Bytes) > , { self . send_bytes :: < N2 > (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bincode < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < T > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) > , T : Clone + Serialize + DeserializeOwned , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bincode (other) } pub fn broadcast_bincode_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , T , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) , Out < T > = (Tag , T) > + 'a , T : Clone + Serialize + DeserializeOwned , { self . broadcast_bincode (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bytes < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) > + 'a , T : Clone , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bytes (other) } pub fn broadcast_bytes_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , Bytes , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) , Out < Bytes > = (Tag , Bytes) > + 'a , T : Clone , { self . broadcast_bytes (other) . map (q ! (| (_ , b) | b)) } } } pub use stream :: { Bounded , NoTick , Stream , Tick , Unbounded } ; pub mod singleton { pub use std :: cell :: RefCell ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use crate :: builder :: FlowLeaves ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial , CycleComplete } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: Stream ; pub use crate :: singleton :: CrossResult ; # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Singleton < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Singleton :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } pub use crate :: singleton :: Singleton ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Singleton { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleComplete < 'a > for Singleton < 'a , T , Bounded , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleCollectionWithInitial < 'a > for Singleton < 'a , T , Bounded , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , initial : Self , l : LocationId ,) -> Self { Singleton :: new (l , ir_leaves , HfPlusNode :: Union (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , }) , initial . ir_node . into_inner () . into () ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Singleton < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Singleton { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , U , W , C , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (Self :: other_ir_node (other)) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Singleton < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CrossSingleton (Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , Box :: new (HfPlusNode :: Unpersist (Box :: new (Self :: other_ir_node (other)))) ,))) ,) } } pub use crate :: singleton :: Optional ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Optional { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } pub fn some (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: new (singleton . location_kind , singleton . ir_leaves , singleton . ir_node . into_inner () ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > From < Singleton < 'a , T , W , C , N > > for Optional < 'a , T , W , C , N > { fn from (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: some (singleton) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Optional < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Optional { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn into_stream (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , Tick , N > > ,) -> Optional < 'a , (T , O) , Bounded , Tick , N > where O : Clone , { let other : Optional < 'a , O , Bounded , Tick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn union (self , other : Optional < 'a , T , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Optional < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_samples (self) -> Stream < 'a , T , Unbounded , NoTick , N > { self . latest_tick () . all_ticks () } pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . latest_tick () . continue_if (samples . first ()) . latest () . tick_samples () } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Unbounded , NoTick , N > > ,) -> Optional < 'a , (T , O) , Unbounded , NoTick , N > where O : Clone , { let other : Optional < 'a , O , Unbounded , NoTick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } self . latest_tick () . cross_singleton (other . latest_tick ()) . latest () } } } pub use singleton :: { Optional , Singleton } ; pub mod location { pub use std :: marker :: PhantomData ; pub use crate :: location :: LocationId ; pub use crate :: location :: Location ; pub use crate :: location :: Process ; # [cfg (stageleft_macro)] impl < P > Clone for Process < P > { fn clone (& self) -> Self { Process { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < P > Location for Process < P > { fn id (& self) -> LocationId { LocationId :: Process (self . id) } } pub use crate :: location :: Cluster ; # [cfg (stageleft_macro)] impl < C > Clone for Cluster < C > { fn clone (& self) -> Self { Cluster { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < C > Location for Cluster < C > { fn id (& self) -> LocationId { LocationId :: Cluster (self . id) } } pub use crate :: location :: CanSend ; # [cfg (stageleft_macro)] impl < P1 , P2 > CanSend < Process < P2 > > for Process < P1 > { type In < T > = T ; type Out < T > = T ; fn is_demux () -> bool { false } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < P1 , C2 > CanSend < Cluster < C2 > > for Process < P1 > { type In < T > = (u32 , T) ; type Out < T > = T ; fn is_demux () -> bool { true } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < C1 , P2 > CanSend < Process < P2 > > for Cluster < C1 > { type In < T > = T ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { false } fn is_tagged () -> bool { true } } # [cfg (stageleft_macro)] impl < C1 , C2 > CanSend < Cluster < C2 > > for Cluster < C1 > { type In < T > = (u32 , T) ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { true } fn is_tagged () -> bool { true } } } pub use location :: { Cluster , Process } ; pub mod deploy { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use stageleft :: Quoted ; pub mod graphs { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use super :: { LocalDeploy , Node , ProcessSpec } ; pub use crate :: deploy :: graphs :: SingleProcessGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for SingleProcessGraph { type Process = SingleNode ; type Cluster = SingleNode ; type Meta = () ; type GraphId = () ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { SingleNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { SingleNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , SingleProcessGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> SingleNode { SingleNode { } } } pub use crate :: deploy :: graphs :: SingleNode ; # [cfg (stageleft_macro)] impl Node for SingleNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } pub use crate :: deploy :: graphs :: MultiGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for MultiGraph { type Process = MultiNode ; type Cluster = MultiNode ; type Meta = () ; type GraphId = usize ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { MultiNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { MultiNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , MultiGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> MultiNode { MultiNode { } } } pub use crate :: deploy :: graphs :: MultiNode ; # [cfg (stageleft_macro)] impl Node for MultiNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } } pub use graphs :: * ; pub use crate :: deploy :: LocalDeploy ; pub use crate :: deploy :: Deploy ; # [cfg (stageleft_macro)] impl < 'a , T : Deploy < 'a , Process = N , Cluster = C , Meta = M , GraphId = R > , N : Node < Meta = M > , C : Node < Meta = M > , M : Default , R , > LocalDeploy < 'a > for T { type Process = N ; type Cluster = C ; type Meta = M ; type GraphId = R ; fn has_trivial_node () -> bool { < T as Deploy < 'a > > :: has_trivial_node () } fn trivial_process (id : usize) -> Self :: Process { < T as Deploy < 'a > > :: trivial_process (id) } fn trivial_cluster (id : usize) -> Self :: Cluster { < T as Deploy < 'a > > :: trivail_cluster (id) } } pub use crate :: deploy :: ProcessSpec ; pub use crate :: deploy :: ClusterSpec ; pub use crate :: deploy :: Node ; } pub use deploy :: { ClusterSpec , Deploy , ProcessSpec } ; pub mod cycle { pub use std :: marker :: PhantomData ; pub use crate :: builder :: FlowLeaves ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: cycle :: CycleComplete ; pub use crate :: cycle :: CycleCollection ; pub use crate :: cycle :: CycleCollectionWithInitial ; pub use crate :: cycle :: HfCycle ; # [cfg (stageleft_macro)] impl < 'a , S : CycleComplete < 'a > > HfCycle < 'a , S > { pub fn complete (self , stream : S) { let ident = self . ident ; S :: complete (stream , ident) } } } pub use cycle :: HfCycle ; pub mod builder { pub use std :: cell :: RefCell ; pub use std :: collections :: HashMap ; pub use std :: marker :: PhantomData ; pub use std :: rc :: Rc ; pub use std :: time :: Duration ; pub use hydroflow :: futures :: stream :: Stream as FuturesStream ; pub use hydroflow :: { tokio , tokio_stream } ; pub use internal :: TokenStream ; pub use proc_macro2 :: Span ; pub use quote :: quote ; pub use runtime_support :: FreeVariable ; pub use stageleft :: * ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Cluster , Location , LocationId , Process } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: { HfCycle , Optional , RuntimeContext , Singleton , Stream } ; pub mod built { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use hydroflow_lang :: graph :: { eliminate_extra_unions_tees , HydroflowGraph } ; pub use super :: deploy :: { DeployFlow , DeployResult } ; pub use crate :: deploy :: { ClusterSpec , Deploy , LocalDeploy , ProcessSpec } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Cluster , Process } ; pub use crate :: HfCompiled ; pub use crate :: builder :: built :: BuiltFlow ; # [cfg (stageleft_macro)] impl < 'a > Drop for BuiltFlow < 'a > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped BuiltFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn ir (& self) -> & Vec < HfPlusLeaf < 'a > > { & self . ir } pub fn optimize_with (mut self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> BuiltFlow < 'a > { self . used = true ; BuiltFlow { ir : f (std :: mem :: take (& mut self . ir)) , processes : std :: mem :: take (& mut self . processes) , clusters : std :: mem :: take (& mut self . clusters) , used : false , _phantom : PhantomData , } } } pub fn build_inner (ir : & mut Vec < HfPlusLeaf >) -> BTreeMap < usize , HydroflowGraph > { let mut builders = BTreeMap :: new () ; let mut built_tees = HashMap :: new () ; let mut next_stmt_id = 0 ; for leaf in ir { leaf . emit (& mut builders , & mut built_tees , & mut next_stmt_id) ; } builders . into_iter () . map (| (k , v) | { let (mut flat_graph , _ , _) = v . build () ; eliminate_extra_unions_tees (& mut flat_graph) ; (k , flat_graph) }) . collect () } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn compile_no_network < D : LocalDeploy < 'a > > (mut self) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; HfCompiled { hydroflow_ir : build_inner (& mut self . ir) , extra_stmts : BTreeMap :: new () , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> BuiltFlow < 'a > { self . optimize_with (crate :: persist_pullup :: persist_pullup) } fn into_deploy < D : LocalDeploy < 'a > > (mut self) -> DeployFlow < 'a , D > { self . used = true ; let processes = if D :: has_trivial_node () { self . processes . iter () . map (| id | (* id , D :: trivial_process (* id))) . collect () } else { HashMap :: new () } ; let clusters = if D :: has_trivial_node () { self . clusters . iter () . map (| id | (* id , D :: trivial_cluster (* id))) . collect () } else { HashMap :: new () } ; DeployFlow { ir : std :: mem :: take (& mut self . ir) , nodes : processes , clusters , used : false , _phantom : PhantomData , } } pub fn with_process < P , D : LocalDeploy < 'a > > (self , process : & Process < P > , spec : impl ProcessSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_process (process , spec) } pub fn with_cluster < C , D : LocalDeploy < 'a > > (self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_cluster (cluster , spec) } pub fn compile < D : Deploy < 'a > + 'a > (self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . into_deploy :: < D > () . compile (env) } pub fn deploy < D : Deploy < 'a , CompileEnv = () > + 'a > (self , env : & mut D :: InstantiateEnv ,) -> DeployResult < 'a , D > { self . into_deploy :: < D > () . deploy (env) } } } pub mod deploy { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use proc_macro2 :: Span ; pub use stageleft :: Quoted ; pub use super :: built :: build_inner ; pub use crate :: deploy :: { LocalDeploy , Node } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: { Cluster , ClusterSpec , Deploy , HfCompiled , Process , ProcessSpec } ; pub use crate :: builder :: deploy :: DeployFlow ; # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > Drop for DeployFlow < 'a , D > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped DeployFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > DeployFlow < 'a , D > { pub fn with_process < P > (mut self , process : & Process < P > , spec : impl ProcessSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < P > () . to_string () ; self . nodes . insert (process . id , spec . build (process . id , & tag_name)) ; self } pub fn with_cluster < C > (mut self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < C > () . to_string () ; self . clusters . insert (cluster . id , spec . build (cluster . id , & tag_name)) ; self } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployFlow < 'a , D > { pub fn compile (mut self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; let mut seen_tees : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | leaf . compile_network :: < D > (env , & mut seen_tees , & self . nodes , & self . clusters)) . collect () ; let extra_stmts = self . extra_stmts (env) ; HfCompiled { hydroflow_ir : build_inner (& mut ir_leaves_networked) , extra_stmts , _phantom : PhantomData , } } fn extra_stmts (& self , env : & < D as Deploy < 'a > > :: CompileEnv) -> BTreeMap < usize , Vec < syn :: Stmt > > { let all_locations_count = self . nodes . len () + self . clusters . len () ; let mut extra_stmts : BTreeMap < usize , Vec < syn :: Stmt > > = BTreeMap :: new () ; for & c_id in self . clusters . keys () { let self_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , c_id) , Span :: call_site () ,) ; let self_id_expr = D :: cluster_self_id (env) . splice () ; extra_stmts . entry (c_id) . or_default () . push (syn :: parse_quote ! { let # self_id_ident = # self_id_expr ; }) ; for other_location in 0 .. all_locations_count { let other_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , c_id) , Span :: call_site () ,) ; let other_id_expr = D :: cluster_ids (env , c_id) . splice () ; extra_stmts . entry (other_location) . or_default () . push (syn :: parse_quote ! { let # other_id_ident = # other_id_expr ; }) ; } } extra_stmts } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a , CompileEnv = () > > DeployFlow < 'a , D > { # [must_use] pub fn deploy (mut self , env : & mut D :: InstantiateEnv) -> DeployResult < 'a , D > { self . used = true ; let mut seen_tees_instantiate : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | { leaf . compile_network :: < D > (& () , & mut seen_tees_instantiate , & self . nodes , & self . clusters ,) }) . collect () ; let mut compiled = build_inner (& mut ir_leaves_networked) ; let mut extra_stmts = self . extra_stmts (& ()) ; let mut meta = D :: Meta :: default () ; let (mut processes , mut clusters) = (std :: mem :: take (& mut self . nodes) . into_iter () . map (| (node_id , node) | { node . instantiate (env , & mut meta , compiled . remove (& node_id) . unwrap () , extra_stmts . remove (& node_id) . unwrap_or_default () ,) ; (node_id , node) }) . collect :: < HashMap < _ , _ > > () , std :: mem :: take (& mut self . clusters) . into_iter () . map (| (cluster_id , cluster) | { cluster . instantiate (env , & mut meta , compiled . remove (& cluster_id) . unwrap () , extra_stmts . remove (& cluster_id) . unwrap_or_default () ,) ; (cluster_id , cluster) }) . collect :: < HashMap < _ , _ > > () ,) ; for node in processes . values_mut () { node . update_meta (& meta) ; } for cluster in clusters . values_mut () { cluster . update_meta (& meta) ; } let mut seen_tees_connect = HashMap :: new () ; for leaf in ir_leaves_networked { leaf . connect_network (& mut seen_tees_connect) ; } DeployResult { processes , clusters , } } } pub use crate :: builder :: deploy :: DeployResult ; # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployResult < 'a , D > { pub fn get_process < P > (& self , p : & Process < P >) -> & D :: Process { let id = match p . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . processes . get (& id) . unwrap () } pub fn get_cluster < C > (& self , c : & Cluster < C >) -> & D :: Cluster { let id = match c . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . clusters . get (& id) . unwrap () } } } # [doc = " Tracks the leaves of the dataflow IR. This is referenced by"] # [doc = " `Stream` and `HfCycle` to build the IR. The inner option will"] # [doc = " be set to `None` when this builder is finalized."] pub type FlowLeaves < 'a > = Rc < RefCell < Option < Vec < HfPlusLeaf < 'a > > > > > ; pub use crate :: builder :: ClusterIds ; # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Vec < u32 > > for ClusterIds < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , & 'a Vec < u32 > > for ClusterIds < 'a > { } # [derive (Copy , Clone)] pub struct ClusterSelfId < 'a > { pub id : usize , pub _phantom : PhantomData < & 'a mut & 'a u32 > , } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < u32 > for ClusterSelfId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , u32 > for ClusterSelfId < 'a > { } pub use crate :: builder :: FlowBuilder ; # [cfg (stageleft_macro)] impl < 'a > Drop for FlowBuilder < 'a > { fn drop (& mut self) { if ! self . finalized { panic ! ("Dropped FlowBuilder without finalizing, you may have forgotten to call `with_default_optimize`, `optimize_with`, or `finalize`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > QuotedContext for FlowBuilder < 'a > { fn create () -> Self { FlowBuilder :: new () } } # [cfg (stageleft_macro)] impl < 'a > FlowBuilder < 'a > { # [allow (clippy :: new_without_default)] pub fn new () -> FlowBuilder < 'a > { FlowBuilder { ir_leaves : Rc :: new (RefCell :: new (Some (Vec :: new ()))) , nodes : RefCell :: new (vec ! []) , clusters : RefCell :: new (vec ! []) , cycle_ids : RefCell :: new (HashMap :: new ()) , next_node_id : RefCell :: new (0) , finalized : false , _phantom : PhantomData , } } pub fn finalize (mut self) -> built :: BuiltFlow < 'a > { self . finalized = true ; built :: BuiltFlow { ir : self . ir_leaves . borrow_mut () . take () . unwrap () , processes : self . nodes . replace (vec ! []) , clusters : self . clusters . replace (vec ! []) , used : false , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> built :: BuiltFlow < 'a > { self . finalize () . with_default_optimize () } pub fn optimize_with (self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> built :: BuiltFlow < 'a > { self . finalize () . optimize_with (f) } pub fn ir_leaves (& self) -> & FlowLeaves < 'a > { & self . ir_leaves } pub fn process < P > (& self) -> Process < P > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . nodes . borrow_mut () . push (id) ; Process { id , _phantom : PhantomData , } } pub fn cluster < C > (& self) -> Cluster < C > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . clusters . borrow_mut () . push (id) ; Cluster { id , _phantom : PhantomData , } } pub fn runtime_context (& self) -> RuntimeContext < 'a > { RuntimeContext { _phantom : PhantomData , } } pub fn cluster_members < C > (& self , cluster : & Cluster < C > ,) -> impl Quoted < 'a , & 'a Vec < u32 > > + Copy + 'a { ClusterIds { id : cluster . id , _phantom : PhantomData , } } pub fn cluster_self_id < C > (& self , cluster : & Cluster < C >) -> impl Quoted < 'a , u32 > + Copy + 'a { ClusterSelfId { id : cluster . id , _phantom : PhantomData , } } pub fn spin < L : Location > (& self , on : & L) -> Stream < 'a , () , Unbounded , NoTick , L > { Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Spin () , location_kind : on . id () , })) ,) } pub fn spin_batch < L : Location > (& self , on : & L , batch_size : impl Quoted < 'a , usize > + Copy + 'a ,) -> Stream < 'a , () , Bounded , Tick , L > { self . spin (on) . flat_map (q ! (move | _ | 0 .. batch_size)) . map (q ! (| _ | ())) . tick_batch () } pub fn source_stream < T , E : FuturesStream < Item = T > + Unpin , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Unbounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Stream (e . into ()) , location_kind : on . id () , })) ,) } pub fn source_iter < T , E : IntoIterator < Item = T > , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Bounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , })) ,) } pub fn singleton < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Singleton < 'a , T , Bounded , NoTick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Singleton :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,)))) ,) } pub fn singleton_first_tick < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Optional < 'a , T , Bounded , Tick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,) } pub fn source_interval < L : Location > (& self , on : & L , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , () , Unbounded , NoTick , L > { let interval = interval . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : on . id () , })) ,) } pub fn source_interval_delayed < L : Location > (& self , on : & L , delay : impl Quoted < 'a , Duration > + Copy + 'a , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , tokio :: time :: Instant , Unbounded , NoTick , L > { self . source_stream (on , q ! (tokio_stream :: wrappers :: IntervalStream :: new (tokio :: time :: interval_at (tokio :: time :: Instant :: now () + delay , interval))) ,) . tick_batch () . first () . latest () } pub fn cycle < S : CycleCollection < 'a > > (& self , on : & S :: Location) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , on . id ()) ,) } pub fn cycle_with_initial < S : CycleCollectionWithInitial < 'a > > (& self , on : & S :: Location , initial : S ,) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , initial , on . id ()) ,) } } } pub use builder :: FlowBuilder ; pub mod ir { pub use core :: panic ; pub use std :: cell :: RefCell ; pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow_lang :: graph :: FlatGraphBuilder ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: ToTokens ; pub use syn :: parse_quote ; pub use crate :: deploy :: Deploy ; pub use crate :: location :: LocationId ; pub use crate :: ir :: DebugExpr ; # [cfg (stageleft_macro)] impl From < syn :: Expr > for DebugExpr { fn from (expr : syn :: Expr) -> DebugExpr { DebugExpr (expr) } } # [cfg (stageleft_macro)] impl Deref for DebugExpr { type Target = syn :: Expr ; fn deref (& self) -> & Self :: Target { & self . 0 } } # [cfg (stageleft_macro)] impl ToTokens for DebugExpr { fn to_tokens (& self , tokens : & mut TokenStream) { self . 0 . to_tokens (tokens) ; } } # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugExpr { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "{}" , self . 0 . to_token_stream ()) } } pub use crate :: ir :: DebugInstantiate ; # [cfg (stageleft_macro)] impl < 'a > std :: fmt :: Debug for DebugInstantiate < 'a > { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<network instantiate>") } } pub use crate :: ir :: DebugPipelineFn ; # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugPipelineFn { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<function>") } } pub use crate :: ir :: HfPlusSource ; pub use crate :: ir :: HfPlusLeaf ; # [cfg (stageleft_macro)] impl < 'a > HfPlusLeaf < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . compile_network :: < D > (compile_env , s , nodes , clusters) ; } , seen_tees ,) } pub fn connect_network (self , seen_tees : & mut SeenTees < 'a >) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . connect_network (s) ; } , seen_tees ,) } pub fn transform_children (self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) -> HfPlusLeaf < 'a > { match self { HfPlusLeaf :: ForEach { f , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: ForEach { f , input } } HfPlusLeaf :: DestSink { sink , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: DestSink { sink , input } } HfPlusLeaf :: CycleSink { ident , location_kind , mut input , } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: CycleSink { ident , location_kind , input , } } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) { match self { HfPlusLeaf :: ForEach { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> for_each (# f) ; }) ; } HfPlusLeaf :: DestSink { sink , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink) ; }) ; } HfPlusLeaf :: CycleSink { ident , location_kind , input , } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; assert_eq ! (input_location_id , * location_id , "cycle_sink location mismatch") ; graph_builders . entry (* location_id) . or_default () . add_statement (parse_quote ! { # ident = # input_ident ; }) ; } } } } pub use crate :: ir :: HfPlusNode ; pub type SeenTees < 'a > = HashMap < * const RefCell < HfPlusNode < 'a > > , Rc < RefCell < HfPlusNode < 'a > > > > ; # [cfg (stageleft_macro)] impl < 'a > HfPlusNode < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (& mut self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) { self . transform_children (| n , s | n . compile_network :: < D > (compile_env , s , nodes , clusters) , seen_tees ,) ; if let HfPlusNode :: Network { from_location , to_location , instantiate_fn , .. } = self { let (sink_expr , source_expr , connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { let ((sink , source) , connect_fn) = match (from_location , to_location) { (LocationId :: Process (from) , LocationId :: Process (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: o2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Process (from) , LocationId :: Cluster (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: o2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Process (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: m2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Cluster (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: m2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } } ; (sink , source , connect_fn) } DebugInstantiate :: Finalized (_ , _ , _) => panic ! ("network already finalized") , } ; * instantiate_fn = DebugInstantiate :: Finalized (sink_expr , source_expr , connect_fn) ; } } pub fn connect_network (& mut self , seen_tees : & mut SeenTees < 'a >) { self . transform_children (| n , s | n . connect_network (s) , seen_tees) ; if let HfPlusNode :: Network { instantiate_fn , .. } = self { match instantiate_fn { DebugInstantiate :: Building () => panic ! ("network not built") , DebugInstantiate :: Finalized (_ , _ , ref connect_fn) => { connect_fn () ; } } } } pub fn transform_children (& mut self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) { match self { HfPlusNode :: Placeholder => { panic ! () ; } HfPlusNode :: Source { .. } => { } HfPlusNode :: CycleSource { .. } => { } HfPlusNode :: Tee { inner } => { if let Some (transformed) = seen_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { * inner = transformed . clone () ; } else { let transformed_cell = Rc :: new (RefCell :: new (HfPlusNode :: Placeholder)) ; seen_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , transformed_cell . clone () ,) ; let mut orig = inner . replace (HfPlusNode :: Placeholder) ; transform (& mut orig , seen_tees) ; * transformed_cell . borrow_mut () = orig ; * inner = transformed_cell ; } } HfPlusNode :: Persist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Unpersist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Delta (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Union (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossProduct (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossSingleton (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Join (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Difference (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: AntiJoin (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Map { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FlatMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Filter { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FilterMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Sort (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: DeferTick (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Enumerate (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Inspect { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Unique (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Fold { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FoldKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Reduce { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: ReduceKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Network { input , .. } => { transform (input . as_mut () , seen_tees) ; } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) -> (syn :: Ident , usize) { match self { HfPlusNode :: Placeholder => { panic ! () } HfPlusNode :: Persist (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let persist_id = * next_stmt_id ; * next_stmt_id += 1 ; let persist_ident = syn :: Ident :: new (& format ! ("stream_{}" , persist_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # persist_ident = # inner_ident -> persist ::<'static > () ; }) ; (persist_ident , location) } HfPlusNode :: Unpersist (_) => { panic ! ("Unpersist is a marker node and should have been optimized away. This is likely a compiler bug.") } HfPlusNode :: Delta (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let delta_id = * next_stmt_id ; * next_stmt_id += 1 ; let delta_ident = syn :: Ident :: new (& format ! ("stream_{}" , delta_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # delta_ident = # inner_ident -> multiset_delta () ; }) ; (delta_ident , location) } HfPlusNode :: Source { source , location_kind , } => { let source_id = * next_stmt_id ; * next_stmt_id += 1 ; let source_ident = syn :: Ident :: new (& format ! ("stream_{}" , source_id) , Span :: call_site ()) ; let source_stmt = match source { HfPlusSource :: Stream (expr) => { parse_quote ! { # source_ident = source_stream (# expr) ; } } HfPlusSource :: Iter (expr) => { parse_quote ! { # source_ident = source_iter (# expr) ; } } HfPlusSource :: Interval (expr) => { parse_quote ! { # source_ident = source_interval (# expr) ; } } HfPlusSource :: Spin () => { parse_quote ! { # source_ident = spin () ; } } } ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; graph_builders . entry (* location_id) . or_default () . add_statement (source_stmt) ; (source_ident , * location_id) } HfPlusNode :: CycleSource { ident , location_kind , } => { let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; (ident . clone () , * location_id) } HfPlusNode :: Tee { inner } => { if let Some (ret) = built_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { ret . clone () } else { let (inner_ident , inner_location_id) = inner . borrow () . emit (graph_builders , built_tees , next_stmt_id) ; let tee_id = * next_stmt_id ; * next_stmt_id += 1 ; let tee_ident = syn :: Ident :: new (& format ! ("stream_{}" , tee_id) , Span :: call_site ()) ; let builder = graph_builders . entry (inner_location_id) . or_default () ; builder . add_statement (parse_quote ! { # tee_ident = # inner_ident -> tee () ; }) ; built_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , (tee_ident . clone () , inner_location_id) ,) ; (tee_ident , inner_location_id) } } HfPlusNode :: Union (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "union inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let union_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # union_ident = union () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [0] # union_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # union_ident ; }) ; (union_ident , left_location_id) } HfPlusNode :: CrossSingleton (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "cross_singleton inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let cross_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # cross_ident = cross_singleton () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [input] # cross_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [single] # cross_ident ; }) ; (cross_ident , left_location_id) } HfPlusNode :: CrossProduct (..) | HfPlusNode :: Join (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: CrossProduct (..)) { parse_quote ! (cross_join_multiset) } else { parse_quote ! (join_multiset) } ; let (HfPlusNode :: CrossProduct (left , right) | HfPlusNode :: Join (left , right)) = self else { unreachable ! () } ; let (left_inner , left_was_persist) = if let HfPlusNode :: Persist (left) = left . as_ref () { (left , true) } else { (left , false) } ; let (right_inner , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left_inner . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right_inner . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "join / cross product inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; match (left_was_persist , right_was_persist) { (true , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'static > () ; }) ; } (true , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'tick > () ; }) ; } (false , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } (false , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } } ; builder . add_statement (parse_quote ! { # left_ident -> [0] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Difference (..) | HfPlusNode :: AntiJoin (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Difference (..)) { parse_quote ! (difference_multiset) } else { parse_quote ! (anti_join_multiset) } ; let (HfPlusNode :: Difference (left , right) | HfPlusNode :: AntiJoin (left , right)) = self else { unreachable ! () } ; let (right , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "difference / anti join inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; if right_was_persist { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } else { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } builder . add_statement (parse_quote ! { # left_ident -> [pos] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [neg] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Map { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let map_id = * next_stmt_id ; * next_stmt_id += 1 ; let map_ident = syn :: Ident :: new (& format ! ("stream_{}" , map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # map_ident = # input_ident -> map (# f) ; }) ; (map_ident , input_location_id) } HfPlusNode :: FlatMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let flat_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let flat_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , flat_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # flat_map_ident = # input_ident -> flat_map (# f) ; }) ; (flat_map_ident , input_location_id) } HfPlusNode :: Filter { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_ident = # input_ident -> filter (# f) ; }) ; (filter_ident , input_location_id) } HfPlusNode :: FilterMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_map_ident = # input_ident -> filter_map (# f) ; }) ; (filter_map_ident , input_location_id) } HfPlusNode :: Sort (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sort_id = * next_stmt_id ; * next_stmt_id += 1 ; let sort_ident = syn :: Ident :: new (& format ! ("stream_{}" , sort_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # sort_ident = # input_ident -> sort () ; }) ; (sort_ident , input_location_id) } HfPlusNode :: DeferTick (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let defer_tick_id = * next_stmt_id ; * next_stmt_id += 1 ; let defer_tick_ident = syn :: Ident :: new (& format ! ("stream_{}" , defer_tick_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # defer_tick_ident = # input_ident -> defer_tick_lazy () ; }) ; (defer_tick_ident , input_location_id) } HfPlusNode :: Enumerate (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let enumerate_id = * next_stmt_id ; * next_stmt_id += 1 ; let enumerate_ident = syn :: Ident :: new (& format ! ("stream_{}" , enumerate_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # enumerate_ident = # input_ident -> enumerate () ; }) ; (enumerate_ident , input_location_id) } HfPlusNode :: Inspect { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let inspect_id = * next_stmt_id ; * next_stmt_id += 1 ; let inspect_ident = syn :: Ident :: new (& format ! ("stream_{}" , inspect_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # inspect_ident = # input_ident -> inspect (# f) ; }) ; (inspect_ident , input_location_id) } HfPlusNode :: Unique (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let unique_id = * next_stmt_id ; * next_stmt_id += 1 ; let unique_ident = syn :: Ident :: new (& format ! ("stream_{}" , unique_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # unique_ident = # input_ident -> unique ::<'tick > () ; }) ; (unique_ident , input_location_id) } HfPlusNode :: Fold { .. } | HfPlusNode :: FoldKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Fold { .. }) { parse_quote ! (fold) } else { parse_quote ! (fold_keyed) } ; let (HfPlusNode :: Fold { init , acc , input } | HfPlusNode :: FoldKeyed { init , acc , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let fold_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'static > (# init , # acc) ; }) ; } else { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'tick > (# init , # acc) ; }) ; } (fold_ident , input_location_id) } HfPlusNode :: Reduce { .. } | HfPlusNode :: ReduceKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Reduce { .. }) { parse_quote ! (reduce) } else { parse_quote ! (reduce_keyed) } ; let (HfPlusNode :: Reduce { f , input } | HfPlusNode :: ReduceKeyed { f , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let reduce_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'static > (# f) ; }) ; } else { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'tick > (# f) ; }) ; } (reduce_ident , input_location_id) } HfPlusNode :: Network { from_location : _ , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input , } => { let (sink_expr , source_expr , _connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { panic ! ("Expected the network to be finalized") } DebugInstantiate :: Finalized (sink , source , connect_fn) => { (sink , source , connect_fn) } } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sender_builder = graph_builders . entry (input_location_id) . or_default () ; if let Some (serialize_pipeline) = serialize_pipeline { sender_builder . add_statement (parse_quote ! { # input_ident -> # serialize_pipeline -> dest_sink (# sink_expr) ; }) ; } else { sender_builder . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink_expr) ; }) ; } let to_id = match to_location { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let receiver_builder = graph_builders . entry (* to_id) . or_default () ; let receiver_stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let receiver_stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , receiver_stream_id) , Span :: call_site ()) ; if let Some (deserialize_pipeline) = deserialize_pipeline { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) -> # deserialize_pipeline ; }) ; } else { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) ; }) ; } (receiver_stream_ident , * to_id) } } } } } pub mod persist_pullup { pub use std :: cell :: RefCell ; pub use std :: collections :: HashSet ; pub use std :: ops :: Deref ; pub use crate :: ir :: * ; pub fn persist_pullup_node < 'a > (node : & mut HfPlusNode < 'a > , seen_tees : & mut SeenTees < 'a > , persist_pulled_tees : & mut HashSet < * const RefCell < HfPlusNode < 'a > > > ,) { node . transform_children (| n , s | persist_pullup_node (n , s , persist_pulled_tees) , seen_tees ,) ; match node { HfPlusNode :: Unpersist (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Unpersist (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Delta (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Delta (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Tee { inner } => { if persist_pulled_tees . contains (& (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >)) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } else { let inner_borrow = inner . borrow () ; if let HfPlusNode :: Persist (_) = inner_borrow . deref () { drop (inner_borrow) ; persist_pulled_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >) ; if let HfPlusNode :: Persist (deref!(behind_persist)) = inner . replace (HfPlusNode :: Placeholder) { * inner . borrow_mut () = behind_persist ; } else { unreachable ! () } * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } } } HfPlusNode :: Map { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Map { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Map { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: FlatMap { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: FlatMap { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: FlatMap { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Filter { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Filter { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Filter { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Network { input : box HfPlusNode :: Persist (_) , .. } => { if let HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Union (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Union (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Union (left , right))) ; } else { unreachable ! () } } HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: CrossProduct (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,) ,)))) ; } else { unreachable ! () } } HfPlusNode :: Join (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Join (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: Join (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,))))) ; } else { unreachable ! () } } _ => { } } } pub fn persist_pullup (ir : Vec < HfPlusLeaf >) -> Vec < HfPlusLeaf > { let mut seen_tees = Default :: default () ; let mut persist_pulled_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| n , s | persist_pullup_node (n , s , & mut persist_pulled_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn persist_pullup_through_map () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } # [test] fn persist_pullup_behind_tee () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; let before_tee = flow . source_iter (& process , q ! (0 .. 10)) . tick_batch () . persist () ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } } } pub mod profiler { pub use std :: cell :: RefCell ; pub use hydroflow :: futures :: channel :: mpsc :: UnboundedSender ; pub use stageleft :: * ; pub use crate as hydroflow_plus ; pub use crate :: ir :: * ; pub use crate :: RuntimeContext ; pub fn increment_counter (count : & mut u64) { * count += 1 ; } pub fn quoted_any_fn < 'a , F : Fn (& usize) + 'a , Q : IntoQuotedMut < 'a , F > > (q : Q) -> Q { q } # [doc = " Add a profiling node before each node to count the cardinality of its input"] pub fn add_profiling_node < 'a > (node : & mut HfPlusNode < 'a > , _context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > , id : & mut u32 , seen_tees : & mut SeenTees < 'a > ,) { let my_id = * id ; * id += 1 ; node . transform_children (| node , seen_tees | { add_profiling_node (node , _context , counters , counter_queue , id , seen_tees) } , seen_tees ,) ; let orig_node = std :: mem :: replace (node , HfPlusNode :: Placeholder) ; * node = HfPlusNode :: Inspect { f : quoted_any_fn (q ! ({ counter_queue . borrow () . unbounded_send ((my_id as usize , counters . borrow () [my_id as usize])) . unwrap () ; counters . borrow_mut () [my_id as usize] = 0 ; move | _ | { hydroflow_plus :: profiler :: increment_counter (& mut counters . borrow_mut () [my_id as usize] ,) ; } })) . splice () . into () , input : Box :: new (orig_node) , } } # [doc = " Count the cardinality of each input and periodically output to a file"] pub fn profiling < 'a > (ir : Vec < HfPlusLeaf < 'a > > , context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > ,) -> Vec < HfPlusLeaf < 'a > > { let mut id = 0 ; let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | { add_profiling_node (node , context , counters , counter_queue , & mut id , seen_tees) } , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn profiler_wrapping_all_operators () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let runtime_context = flow . runtime_context () ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (& built . ir ()) ; let counters = RuntimeData :: new ("Fake") ; let counter_queue = RuntimeData :: new ("Fake") ; let pushed_down = built . with_default_optimize () . optimize_with (| ir | super :: profiling (ir , runtime_context , counters , counter_queue)) ; insta :: assert_debug_snapshot ! (& pushed_down . ir ()) ; let _ = pushed_down . compile_no_network :: < MultiGraph > () ; } } } pub mod properties { pub use std :: collections :: HashSet ; pub use stageleft :: * ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , SeenTees } ; pub use crate :: properties :: PropertyDatabase ; # [doc = " Allows us to convert the hydroflow datatype for folds to a binary operation for the algebra"] # [doc = " property tests."] # [allow (dead_code)] pub fn convert_hf_to_binary < I , A : Default , F : Fn (& mut A , I) > (f : F) -> impl Fn (I , I) -> A { move | a , b | { let mut acc = Default :: default () ; f (& mut acc , a) ; f (& mut acc , b) ; acc } } # [cfg (stageleft_macro)] impl PropertyDatabase { # [doc = " Tags the expression as commutative."] pub fn add_commutative_tag < 'a , I , A , F : Fn (& mut A , I) , Q : Quoted < 'a , F > + Clone > (& mut self , expr : Q ,) -> Q { let expr_clone = expr . clone () ; self . commutative . insert (expr_clone . splice ()) ; expr } pub fn is_tagged_commutative (& self , expr : & syn :: Expr) -> bool { self . commutative . contains (expr) } } pub fn properties_optimize_node < 'a > (node : & mut HfPlusNode < 'a > , db : & PropertyDatabase , seen_tees : & mut SeenTees < 'a > ,) { node . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , seen_tees ,) ; match node { HfPlusNode :: ReduceKeyed { f , .. } if db . is_tagged_commutative (& f . 0) => { dbg ! ("IDENTIFIED COMMUTATIVE OPTIMIZATION for {:?}" , & f) ; } _ => { } } } pub fn properties_optimize < 'a > (ir : Vec < HfPlusLeaf < 'a > > , db : & PropertyDatabase ,) -> Vec < HfPlusLeaf < 'a > > { let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use super :: * ; use crate :: deploy :: SingleProcessGraph ; use crate :: FlowBuilder ; # [test] fn test_property_database () { let mut db = PropertyDatabase :: default () ; assert ! (! db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; let _ = db . add_commutative_tag (q ! (| a : & mut i32 , b : i32 | * a += b)) ; assert ! (db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; } # [test] fn test_property_optimized () { let flow = FlowBuilder :: new () ; let mut database = PropertyDatabase :: default () ; let process = flow . process :: < () > () ; let counter_func = q ! (| count : & mut i32 , _ | * count += 1) ; let _ = database . add_commutative_tag (counter_func) ; flow . source_iter (& process , q ! (vec ! [])) . map (q ! (| string : String | (string , ()))) . tick_batch () . fold_keyed (q ! (|| 0) , counter_func) . all_ticks () . for_each (q ! (| (string , count) | println ! ("{}: {}" , string , count))) ; let built = flow . finalize () . optimize_with (| ir | properties_optimize (ir , & database)) . with_default_optimize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let _ = built . compile_no_network :: < SingleProcessGraph > () ; } } } pub use crate :: RuntimeContext ; # [cfg (stageleft_macro)] impl Copy for RuntimeContext < '_ > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Context > for RuntimeContext < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (quote ! (& context))) } } pub use crate :: HfCompiled ; # [cfg (stageleft_macro)] impl < 'a , ID > HfCompiled < 'a , ID > { pub fn hydroflow_ir (& self) -> & BTreeMap < usize , HydroflowGraph > { & self . hydroflow_ir } } # [cfg (stageleft_macro)] impl < 'a > HfCompiled < 'a , usize > { pub fn with_dynamic_id (self , id : impl Quoted < 'a , usize >) -> HfBuiltWithId < 'a > { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; let mut conditioned_tokens = None ; for (subgraph_id , flat_graph) in self . hydroflow_ir { let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; let my_extra_stmts = self . extra_stmts . get (& subgraph_id) . cloned () . unwrap_or_default () ; if let Some (conditioned_tokens) = conditioned_tokens . as_mut () { * conditioned_tokens = syn :: parse_quote ! { # conditioned_tokens else if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } } ; } else { conditioned_tokens = Some (syn :: parse_quote ! { if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } }) ; } } let conditioned_tokens : TokenStream = conditioned_tokens . unwrap () ; let id = id . splice () ; HfBuiltWithId { tokens : syn :: parse_quote ! ({ let __given_id = # id ; # conditioned_tokens else { panic ! ("Invalid node id: {}" , __given_id) ; } }) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfCompiled < 'a , () > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfCompiled < 'a , () > { fn to_tokens (mut self) -> (Option < TokenStream > , Option < TokenStream >) { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; if self . hydroflow_ir . len () != 1 { panic ! ("Expected exactly one subgraph in the Hydroflow IR") ; } let flat_graph = self . hydroflow_ir . remove (& 0) . unwrap () ; let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; (None , Some (tokens)) } } pub use crate :: HfBuiltWithId ; # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfBuiltWithId < 'a > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfBuiltWithId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (self . tokens)) } }
[INFO] [stdout]   |
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] error: `box` patterns have been removed (feature `box_patterns`)
[INFO] [stdout]  --> /opt/rustwide/target/debug/build/hydroflow_plus/5672655b657d1e44/out/lib_pub.rs:1:93028
[INFO] [stdout]   |
[INFO] [stdout] 1 | ...r . clone () , })) ; } } } HfPlusNode :: Map { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Map { f...
[INFO] [stdout]   |                                                                   ^^^
[INFO] [stdout]   |
[INFO] [stdout]   = help: enable feature `deref_patterns` instead and...
[INFO] [stdout] help: ...if possible just remove keyword `box`...
[INFO] [stdout]   |
[INFO] [stdout] 1 - pub use std :: collections :: BTreeMap ; pub use std :: marker :: PhantomData ; pub use hydroflow :: scheduled :: context :: Context ; pub use hydroflow :: scheduled :: graph :: Hydroflow ; pub use hydroflow :: * ; pub use lang :: graph :: { partition_graph , HydroflowGraph } ; pub use proc_macro2 :: TokenStream ; pub use quote :: quote ; pub use stageleft :: runtime_support :: FreeVariable ; pub use stageleft :: Quoted ; pub mod runtime_support { pub use bincode ; } pub mod stream { pub use std :: cell :: RefCell ; pub use std :: hash :: Hash ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow :: bytes :: Bytes ; pub use hydroflow :: futures :: Sink ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: quote ; pub use serde :: de :: DeserializeOwned ; pub use serde :: Serialize ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use syn :: parse_quote ; pub use crate :: builder :: { ClusterIds , FlowLeaves } ; pub use crate :: cycle :: { CycleCollection , CycleComplete } ; pub use crate :: ir :: { DebugInstantiate , HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { CanSend , Location , LocationId } ; pub use crate :: { Cluster , Optional , Singleton } ; pub use crate :: stream :: Unbounded ; pub use crate :: stream :: Bounded ; pub use crate :: stream :: NoTick ; pub use crate :: stream :: Tick ; pub use crate :: stream :: Stream ; # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Stream { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Stream < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Stream { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , C , N > > ,) -> Stream < 'a , (T , O) , W , C , N > where O : Clone , { let other : Optional < 'a , O , Bounded , C , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn cross_product < O > (self , other : Stream < 'a , O , W , C , N >) -> Stream < 'a , (T , O) , W , C , N > where T : Clone , O : Clone , { if self . location_kind != other . location_kind { panic ! ("cross_product must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossProduct (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn union (self , other : Stream < 'a , T , W , C , N >) -> Stream < 'a , T , W , C , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn dest_sink < S : Unpin + Sink < T > + 'a > (self , sink : impl Quoted < 'a , S >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: DestSink { sink : sink . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn first (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } # [doc = " Allow this stream through if the other stream has elements, otherwise the output is empty."] pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } # [doc = " Allow this stream through if the other stream is empty, otherwise the output is empty."] pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn enumerate (self) -> Stream < 'a , (usize , T) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Enumerate (Box :: new (self . ir_node . into_inner ())) ,) } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn sort (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Ord , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Sort (Box :: new (self . ir_node . into_inner ())) ,) } pub fn count (self) -> Singleton < 'a , usize , Bounded , Tick , N > { self . fold (q ! (|| 0usize) , q ! (| count , _ | * count += 1)) } pub fn delta (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } pub fn unique (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Eq + Hash , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unique (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn tick_batch (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_prefix (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { self . tick_batch () . persist () } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn for_each < F : Fn (T) + 'a > (self , f : impl IntoQuotedMut < 'a , F >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: ForEach { input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , f : f . splice () . into () , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Unbounded , NoTick , N > { pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . tick_batch () . continue_if (samples . first ()) . all_ticks () } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Unbounded , NoTick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , C , N : Location > Stream < 'a , T , Bounded , C , N > { pub fn filter_not_in (self , other : Stream < 'a , T , Bounded , C , N >) -> Stream < 'a , T , Bounded , C , N > where T : Eq + Hash , { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Difference (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Stream < 'a , & T , W , C , N > { pub fn cloned (self) -> Stream < 'a , T , W , C , N > { self . map (q ! (| d | d . clone ())) } } # [cfg (stageleft_macro)] impl < 'a , K , V1 , W , C , N : Location > Stream < 'a , (K , V1) , W , C , N > { pub fn join < W2 , V2 > (self , n : Stream < 'a , (K , V2) , W2 , C , N > ,) -> Stream < 'a , (K , (V1 , V2)) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Join (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } pub fn anti_join < W2 > (self , n : Stream < 'a , K , W2 , C , N >) -> Stream < 'a , (K , V1) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("anti_join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: AntiJoin (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , K : Eq + Hash , V , N : Location > Stream < 'a , (K , V) , Bounded , Tick , N > { pub fn fold_keyed < A , I : Fn () -> A + 'a , F : Fn (& mut A , V) + 'a > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , A) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FoldKeyed { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce_keyed < F : Fn (& mut V , V) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , V) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: ReduceKeyed { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } pub fn get_this_crate () -> TokenStream { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , Span :: call_site ()) ; quote ! { # ident } } } } pub fn serialize_bincode < T : Serialize > (is_demux : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if is_demux { parse_quote ! { map (| (id , data) | { (id , # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into ()) }) } } else { parse_quote ! { map (| data | { # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into () }) } } } pub fn deserialize_bincode < T : DeserializeOwned > (tagged : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if tagged { parse_quote ! { map (| res | { let (id , b) = res . unwrap () ; (id , # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& b) . unwrap ()) }) } } else { parse_quote ! { map (| res | { # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& res . unwrap ()) . unwrap () }) } } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn send_bincode < N2 : Location , CoreType > (self , other : & N2 ,) -> Stream < 'a , N :: Out < CoreType > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T > , CoreType : Serialize + DeserializeOwned , { let serialize_pipeline = Some (serialize_bincode :: < CoreType > (N :: is_demux ())) ; let deserialize_pipeline = Some (deserialize_bincode :: < CoreType > (N :: is_tagged ())) ; Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bytes < N2 : Location > (self , other : & N2 ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T > , { Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline : None , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline : if N :: is_tagged () { Some (parse_quote ! (map (| (id , b) | (id , b . unwrap () . freeze ())))) } else { Some (parse_quote ! (map (| b | b . unwrap () . freeze ()))) } , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bincode_interleaved < N2 : Location , Tag , CoreType > (self , other : & N2 ,) -> Stream < 'a , CoreType , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T , Out < CoreType > = (Tag , CoreType) > , CoreType : Serialize + DeserializeOwned , { self . send_bincode :: < N2 , CoreType > (other) . map (q ! (| (_ , b) | b)) } pub fn send_bytes_interleaved < N2 : Location , Tag > (self , other : & N2 ,) -> Stream < 'a , Bytes , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T , Out < Bytes > = (Tag , Bytes) > , { self . send_bytes :: < N2 > (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bincode < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < T > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) > , T : Clone + Serialize + DeserializeOwned , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bincode (other) } pub fn broadcast_bincode_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , T , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) , Out < T > = (Tag , T) > + 'a , T : Clone + Serialize + DeserializeOwned , { self . broadcast_bincode (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bytes < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) > + 'a , T : Clone , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bytes (other) } pub fn broadcast_bytes_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , Bytes , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) , Out < Bytes > = (Tag , Bytes) > + 'a , T : Clone , { self . broadcast_bytes (other) . map (q ! (| (_ , b) | b)) } } } pub use stream :: { Bounded , NoTick , Stream , Tick , Unbounded } ; pub mod singleton { pub use std :: cell :: RefCell ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use crate :: builder :: FlowLeaves ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial , CycleComplete } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: Stream ; pub use crate :: singleton :: CrossResult ; # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Singleton < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Singleton :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } pub use crate :: singleton :: Singleton ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Singleton { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleComplete < 'a > for Singleton < 'a , T , Bounded , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleCollectionWithInitial < 'a > for Singleton < 'a , T , Bounded , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , initial : Self , l : LocationId ,) -> Self { Singleton :: new (l , ir_leaves , HfPlusNode :: Union (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , }) , initial . ir_node . into_inner () . into () ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Singleton < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Singleton { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , U , W , C , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (Self :: other_ir_node (other)) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Singleton < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CrossSingleton (Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , Box :: new (HfPlusNode :: Unpersist (Box :: new (Self :: other_ir_node (other)))) ,))) ,) } } pub use crate :: singleton :: Optional ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Optional { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } pub fn some (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: new (singleton . location_kind , singleton . ir_leaves , singleton . ir_node . into_inner () ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > From < Singleton < 'a , T , W , C , N > > for Optional < 'a , T , W , C , N > { fn from (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: some (singleton) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Optional < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Optional { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn into_stream (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , Tick , N > > ,) -> Optional < 'a , (T , O) , Bounded , Tick , N > where O : Clone , { let other : Optional < 'a , O , Bounded , Tick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn union (self , other : Optional < 'a , T , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Optional < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_samples (self) -> Stream < 'a , T , Unbounded , NoTick , N > { self . latest_tick () . all_ticks () } pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . latest_tick () . continue_if (samples . first ()) . latest () . tick_samples () } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Unbounded , NoTick , N > > ,) -> Optional < 'a , (T , O) , Unbounded , NoTick , N > where O : Clone , { let other : Optional < 'a , O , Unbounded , NoTick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } self . latest_tick () . cross_singleton (other . latest_tick ()) . latest () } } } pub use singleton :: { Optional , Singleton } ; pub mod location { pub use std :: marker :: PhantomData ; pub use crate :: location :: LocationId ; pub use crate :: location :: Location ; pub use crate :: location :: Process ; # [cfg (stageleft_macro)] impl < P > Clone for Process < P > { fn clone (& self) -> Self { Process { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < P > Location for Process < P > { fn id (& self) -> LocationId { LocationId :: Process (self . id) } } pub use crate :: location :: Cluster ; # [cfg (stageleft_macro)] impl < C > Clone for Cluster < C > { fn clone (& self) -> Self { Cluster { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < C > Location for Cluster < C > { fn id (& self) -> LocationId { LocationId :: Cluster (self . id) } } pub use crate :: location :: CanSend ; # [cfg (stageleft_macro)] impl < P1 , P2 > CanSend < Process < P2 > > for Process < P1 > { type In < T > = T ; type Out < T > = T ; fn is_demux () -> bool { false } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < P1 , C2 > CanSend < Cluster < C2 > > for Process < P1 > { type In < T > = (u32 , T) ; type Out < T > = T ; fn is_demux () -> bool { true } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < C1 , P2 > CanSend < Process < P2 > > for Cluster < C1 > { type In < T > = T ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { false } fn is_tagged () -> bool { true } } # [cfg (stageleft_macro)] impl < C1 , C2 > CanSend < Cluster < C2 > > for Cluster < C1 > { type In < T > = (u32 , T) ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { true } fn is_tagged () -> bool { true } } } pub use location :: { Cluster , Process } ; pub mod deploy { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use stageleft :: Quoted ; pub mod graphs { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use super :: { LocalDeploy , Node , ProcessSpec } ; pub use crate :: deploy :: graphs :: SingleProcessGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for SingleProcessGraph { type Process = SingleNode ; type Cluster = SingleNode ; type Meta = () ; type GraphId = () ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { SingleNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { SingleNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , SingleProcessGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> SingleNode { SingleNode { } } } pub use crate :: deploy :: graphs :: SingleNode ; # [cfg (stageleft_macro)] impl Node for SingleNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } pub use crate :: deploy :: graphs :: MultiGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for MultiGraph { type Process = MultiNode ; type Cluster = MultiNode ; type Meta = () ; type GraphId = usize ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { MultiNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { MultiNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , MultiGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> MultiNode { MultiNode { } } } pub use crate :: deploy :: graphs :: MultiNode ; # [cfg (stageleft_macro)] impl Node for MultiNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } } pub use graphs :: * ; pub use crate :: deploy :: LocalDeploy ; pub use crate :: deploy :: Deploy ; # [cfg (stageleft_macro)] impl < 'a , T : Deploy < 'a , Process = N , Cluster = C , Meta = M , GraphId = R > , N : Node < Meta = M > , C : Node < Meta = M > , M : Default , R , > LocalDeploy < 'a > for T { type Process = N ; type Cluster = C ; type Meta = M ; type GraphId = R ; fn has_trivial_node () -> bool { < T as Deploy < 'a > > :: has_trivial_node () } fn trivial_process (id : usize) -> Self :: Process { < T as Deploy < 'a > > :: trivial_process (id) } fn trivial_cluster (id : usize) -> Self :: Cluster { < T as Deploy < 'a > > :: trivail_cluster (id) } } pub use crate :: deploy :: ProcessSpec ; pub use crate :: deploy :: ClusterSpec ; pub use crate :: deploy :: Node ; } pub use deploy :: { ClusterSpec , Deploy , ProcessSpec } ; pub mod cycle { pub use std :: marker :: PhantomData ; pub use crate :: builder :: FlowLeaves ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: cycle :: CycleComplete ; pub use crate :: cycle :: CycleCollection ; pub use crate :: cycle :: CycleCollectionWithInitial ; pub use crate :: cycle :: HfCycle ; # [cfg (stageleft_macro)] impl < 'a , S : CycleComplete < 'a > > HfCycle < 'a , S > { pub fn complete (self , stream : S) { let ident = self . ident ; S :: complete (stream , ident) } } } pub use cycle :: HfCycle ; pub mod builder { pub use std :: cell :: RefCell ; pub use std :: collections :: HashMap ; pub use std :: marker :: PhantomData ; pub use std :: rc :: Rc ; pub use std :: time :: Duration ; pub use hydroflow :: futures :: stream :: Stream as FuturesStream ; pub use hydroflow :: { tokio , tokio_stream } ; pub use internal :: TokenStream ; pub use proc_macro2 :: Span ; pub use quote :: quote ; pub use runtime_support :: FreeVariable ; pub use stageleft :: * ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Cluster , Location , LocationId , Process } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: { HfCycle , Optional , RuntimeContext , Singleton , Stream } ; pub mod built { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use hydroflow_lang :: graph :: { eliminate_extra_unions_tees , HydroflowGraph } ; pub use super :: deploy :: { DeployFlow , DeployResult } ; pub use crate :: deploy :: { ClusterSpec , Deploy , LocalDeploy , ProcessSpec } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Cluster , Process } ; pub use crate :: HfCompiled ; pub use crate :: builder :: built :: BuiltFlow ; # [cfg (stageleft_macro)] impl < 'a > Drop for BuiltFlow < 'a > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped BuiltFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn ir (& self) -> & Vec < HfPlusLeaf < 'a > > { & self . ir } pub fn optimize_with (mut self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> BuiltFlow < 'a > { self . used = true ; BuiltFlow { ir : f (std :: mem :: take (& mut self . ir)) , processes : std :: mem :: take (& mut self . processes) , clusters : std :: mem :: take (& mut self . clusters) , used : false , _phantom : PhantomData , } } } pub fn build_inner (ir : & mut Vec < HfPlusLeaf >) -> BTreeMap < usize , HydroflowGraph > { let mut builders = BTreeMap :: new () ; let mut built_tees = HashMap :: new () ; let mut next_stmt_id = 0 ; for leaf in ir { leaf . emit (& mut builders , & mut built_tees , & mut next_stmt_id) ; } builders . into_iter () . map (| (k , v) | { let (mut flat_graph , _ , _) = v . build () ; eliminate_extra_unions_tees (& mut flat_graph) ; (k , flat_graph) }) . collect () } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn compile_no_network < D : LocalDeploy < 'a > > (mut self) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; HfCompiled { hydroflow_ir : build_inner (& mut self . ir) , extra_stmts : BTreeMap :: new () , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> BuiltFlow < 'a > { self . optimize_with (crate :: persist_pullup :: persist_pullup) } fn into_deploy < D : LocalDeploy < 'a > > (mut self) -> DeployFlow < 'a , D > { self . used = true ; let processes = if D :: has_trivial_node () { self . processes . iter () . map (| id | (* id , D :: trivial_process (* id))) . collect () } else { HashMap :: new () } ; let clusters = if D :: has_trivial_node () { self . clusters . iter () . map (| id | (* id , D :: trivial_cluster (* id))) . collect () } else { HashMap :: new () } ; DeployFlow { ir : std :: mem :: take (& mut self . ir) , nodes : processes , clusters , used : false , _phantom : PhantomData , } } pub fn with_process < P , D : LocalDeploy < 'a > > (self , process : & Process < P > , spec : impl ProcessSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_process (process , spec) } pub fn with_cluster < C , D : LocalDeploy < 'a > > (self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_cluster (cluster , spec) } pub fn compile < D : Deploy < 'a > + 'a > (self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . into_deploy :: < D > () . compile (env) } pub fn deploy < D : Deploy < 'a , CompileEnv = () > + 'a > (self , env : & mut D :: InstantiateEnv ,) -> DeployResult < 'a , D > { self . into_deploy :: < D > () . deploy (env) } } } pub mod deploy { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use proc_macro2 :: Span ; pub use stageleft :: Quoted ; pub use super :: built :: build_inner ; pub use crate :: deploy :: { LocalDeploy , Node } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: { Cluster , ClusterSpec , Deploy , HfCompiled , Process , ProcessSpec } ; pub use crate :: builder :: deploy :: DeployFlow ; # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > Drop for DeployFlow < 'a , D > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped DeployFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > DeployFlow < 'a , D > { pub fn with_process < P > (mut self , process : & Process < P > , spec : impl ProcessSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < P > () . to_string () ; self . nodes . insert (process . id , spec . build (process . id , & tag_name)) ; self } pub fn with_cluster < C > (mut self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < C > () . to_string () ; self . clusters . insert (cluster . id , spec . build (cluster . id , & tag_name)) ; self } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployFlow < 'a , D > { pub fn compile (mut self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; let mut seen_tees : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | leaf . compile_network :: < D > (env , & mut seen_tees , & self . nodes , & self . clusters)) . collect () ; let extra_stmts = self . extra_stmts (env) ; HfCompiled { hydroflow_ir : build_inner (& mut ir_leaves_networked) , extra_stmts , _phantom : PhantomData , } } fn extra_stmts (& self , env : & < D as Deploy < 'a > > :: CompileEnv) -> BTreeMap < usize , Vec < syn :: Stmt > > { let all_locations_count = self . nodes . len () + self . clusters . len () ; let mut extra_stmts : BTreeMap < usize , Vec < syn :: Stmt > > = BTreeMap :: new () ; for & c_id in self . clusters . keys () { let self_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , c_id) , Span :: call_site () ,) ; let self_id_expr = D :: cluster_self_id (env) . splice () ; extra_stmts . entry (c_id) . or_default () . push (syn :: parse_quote ! { let # self_id_ident = # self_id_expr ; }) ; for other_location in 0 .. all_locations_count { let other_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , c_id) , Span :: call_site () ,) ; let other_id_expr = D :: cluster_ids (env , c_id) . splice () ; extra_stmts . entry (other_location) . or_default () . push (syn :: parse_quote ! { let # other_id_ident = # other_id_expr ; }) ; } } extra_stmts } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a , CompileEnv = () > > DeployFlow < 'a , D > { # [must_use] pub fn deploy (mut self , env : & mut D :: InstantiateEnv) -> DeployResult < 'a , D > { self . used = true ; let mut seen_tees_instantiate : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | { leaf . compile_network :: < D > (& () , & mut seen_tees_instantiate , & self . nodes , & self . clusters ,) }) . collect () ; let mut compiled = build_inner (& mut ir_leaves_networked) ; let mut extra_stmts = self . extra_stmts (& ()) ; let mut meta = D :: Meta :: default () ; let (mut processes , mut clusters) = (std :: mem :: take (& mut self . nodes) . into_iter () . map (| (node_id , node) | { node . instantiate (env , & mut meta , compiled . remove (& node_id) . unwrap () , extra_stmts . remove (& node_id) . unwrap_or_default () ,) ; (node_id , node) }) . collect :: < HashMap < _ , _ > > () , std :: mem :: take (& mut self . clusters) . into_iter () . map (| (cluster_id , cluster) | { cluster . instantiate (env , & mut meta , compiled . remove (& cluster_id) . unwrap () , extra_stmts . remove (& cluster_id) . unwrap_or_default () ,) ; (cluster_id , cluster) }) . collect :: < HashMap < _ , _ > > () ,) ; for node in processes . values_mut () { node . update_meta (& meta) ; } for cluster in clusters . values_mut () { cluster . update_meta (& meta) ; } let mut seen_tees_connect = HashMap :: new () ; for leaf in ir_leaves_networked { leaf . connect_network (& mut seen_tees_connect) ; } DeployResult { processes , clusters , } } } pub use crate :: builder :: deploy :: DeployResult ; # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployResult < 'a , D > { pub fn get_process < P > (& self , p : & Process < P >) -> & D :: Process { let id = match p . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . processes . get (& id) . unwrap () } pub fn get_cluster < C > (& self , c : & Cluster < C >) -> & D :: Cluster { let id = match c . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . clusters . get (& id) . unwrap () } } } # [doc = " Tracks the leaves of the dataflow IR. This is referenced by"] # [doc = " `Stream` and `HfCycle` to build the IR. The inner option will"] # [doc = " be set to `None` when this builder is finalized."] pub type FlowLeaves < 'a > = Rc < RefCell < Option < Vec < HfPlusLeaf < 'a > > > > > ; pub use crate :: builder :: ClusterIds ; # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Vec < u32 > > for ClusterIds < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , & 'a Vec < u32 > > for ClusterIds < 'a > { } # [derive (Copy , Clone)] pub struct ClusterSelfId < 'a > { pub id : usize , pub _phantom : PhantomData < & 'a mut & 'a u32 > , } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < u32 > for ClusterSelfId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , u32 > for ClusterSelfId < 'a > { } pub use crate :: builder :: FlowBuilder ; # [cfg (stageleft_macro)] impl < 'a > Drop for FlowBuilder < 'a > { fn drop (& mut self) { if ! self . finalized { panic ! ("Dropped FlowBuilder without finalizing, you may have forgotten to call `with_default_optimize`, `optimize_with`, or `finalize`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > QuotedContext for FlowBuilder < 'a > { fn create () -> Self { FlowBuilder :: new () } } # [cfg (stageleft_macro)] impl < 'a > FlowBuilder < 'a > { # [allow (clippy :: new_without_default)] pub fn new () -> FlowBuilder < 'a > { FlowBuilder { ir_leaves : Rc :: new (RefCell :: new (Some (Vec :: new ()))) , nodes : RefCell :: new (vec ! []) , clusters : RefCell :: new (vec ! []) , cycle_ids : RefCell :: new (HashMap :: new ()) , next_node_id : RefCell :: new (0) , finalized : false , _phantom : PhantomData , } } pub fn finalize (mut self) -> built :: BuiltFlow < 'a > { self . finalized = true ; built :: BuiltFlow { ir : self . ir_leaves . borrow_mut () . take () . unwrap () , processes : self . nodes . replace (vec ! []) , clusters : self . clusters . replace (vec ! []) , used : false , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> built :: BuiltFlow < 'a > { self . finalize () . with_default_optimize () } pub fn optimize_with (self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> built :: BuiltFlow < 'a > { self . finalize () . optimize_with (f) } pub fn ir_leaves (& self) -> & FlowLeaves < 'a > { & self . ir_leaves } pub fn process < P > (& self) -> Process < P > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . nodes . borrow_mut () . push (id) ; Process { id , _phantom : PhantomData , } } pub fn cluster < C > (& self) -> Cluster < C > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . clusters . borrow_mut () . push (id) ; Cluster { id , _phantom : PhantomData , } } pub fn runtime_context (& self) -> RuntimeContext < 'a > { RuntimeContext { _phantom : PhantomData , } } pub fn cluster_members < C > (& self , cluster : & Cluster < C > ,) -> impl Quoted < 'a , & 'a Vec < u32 > > + Copy + 'a { ClusterIds { id : cluster . id , _phantom : PhantomData , } } pub fn cluster_self_id < C > (& self , cluster : & Cluster < C >) -> impl Quoted < 'a , u32 > + Copy + 'a { ClusterSelfId { id : cluster . id , _phantom : PhantomData , } } pub fn spin < L : Location > (& self , on : & L) -> Stream < 'a , () , Unbounded , NoTick , L > { Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Spin () , location_kind : on . id () , })) ,) } pub fn spin_batch < L : Location > (& self , on : & L , batch_size : impl Quoted < 'a , usize > + Copy + 'a ,) -> Stream < 'a , () , Bounded , Tick , L > { self . spin (on) . flat_map (q ! (move | _ | 0 .. batch_size)) . map (q ! (| _ | ())) . tick_batch () } pub fn source_stream < T , E : FuturesStream < Item = T > + Unpin , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Unbounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Stream (e . into ()) , location_kind : on . id () , })) ,) } pub fn source_iter < T , E : IntoIterator < Item = T > , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Bounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , })) ,) } pub fn singleton < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Singleton < 'a , T , Bounded , NoTick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Singleton :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,)))) ,) } pub fn singleton_first_tick < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Optional < 'a , T , Bounded , Tick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,) } pub fn source_interval < L : Location > (& self , on : & L , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , () , Unbounded , NoTick , L > { let interval = interval . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : on . id () , })) ,) } pub fn source_interval_delayed < L : Location > (& self , on : & L , delay : impl Quoted < 'a , Duration > + Copy + 'a , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , tokio :: time :: Instant , Unbounded , NoTick , L > { self . source_stream (on , q ! (tokio_stream :: wrappers :: IntervalStream :: new (tokio :: time :: interval_at (tokio :: time :: Instant :: now () + delay , interval))) ,) . tick_batch () . first () . latest () } pub fn cycle < S : CycleCollection < 'a > > (& self , on : & S :: Location) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , on . id ()) ,) } pub fn cycle_with_initial < S : CycleCollectionWithInitial < 'a > > (& self , on : & S :: Location , initial : S ,) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , initial , on . id ()) ,) } } } pub use builder :: FlowBuilder ; pub mod ir { pub use core :: panic ; pub use std :: cell :: RefCell ; pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow_lang :: graph :: FlatGraphBuilder ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: ToTokens ; pub use syn :: parse_quote ; pub use crate :: deploy :: Deploy ; pub use crate :: location :: LocationId ; pub use crate :: ir :: DebugExpr ; # [cfg (stageleft_macro)] impl From < syn :: Expr > for DebugExpr { fn from (expr : syn :: Expr) -> DebugExpr { DebugExpr (expr) } } # [cfg (stageleft_macro)] impl Deref for DebugExpr { type Target = syn :: Expr ; fn deref (& self) -> & Self :: Target { & self . 0 } } # [cfg (stageleft_macro)] impl ToTokens for DebugExpr { fn to_tokens (& self , tokens : & mut TokenStream) { self . 0 . to_tokens (tokens) ; } } # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugExpr { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "{}" , self . 0 . to_token_stream ()) } } pub use crate :: ir :: DebugInstantiate ; # [cfg (stageleft_macro)] impl < 'a > std :: fmt :: Debug for DebugInstantiate < 'a > { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<network instantiate>") } } pub use crate :: ir :: DebugPipelineFn ; # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugPipelineFn { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<function>") } } pub use crate :: ir :: HfPlusSource ; pub use crate :: ir :: HfPlusLeaf ; # [cfg (stageleft_macro)] impl < 'a > HfPlusLeaf < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . compile_network :: < D > (compile_env , s , nodes , clusters) ; } , seen_tees ,) } pub fn connect_network (self , seen_tees : & mut SeenTees < 'a >) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . connect_network (s) ; } , seen_tees ,) } pub fn transform_children (self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) -> HfPlusLeaf < 'a > { match self { HfPlusLeaf :: ForEach { f , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: ForEach { f , input } } HfPlusLeaf :: DestSink { sink , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: DestSink { sink , input } } HfPlusLeaf :: CycleSink { ident , location_kind , mut input , } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: CycleSink { ident , location_kind , input , } } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) { match self { HfPlusLeaf :: ForEach { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> for_each (# f) ; }) ; } HfPlusLeaf :: DestSink { sink , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink) ; }) ; } HfPlusLeaf :: CycleSink { ident , location_kind , input , } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; assert_eq ! (input_location_id , * location_id , "cycle_sink location mismatch") ; graph_builders . entry (* location_id) . or_default () . add_statement (parse_quote ! { # ident = # input_ident ; }) ; } } } } pub use crate :: ir :: HfPlusNode ; pub type SeenTees < 'a > = HashMap < * const RefCell < HfPlusNode < 'a > > , Rc < RefCell < HfPlusNode < 'a > > > > ; # [cfg (stageleft_macro)] impl < 'a > HfPlusNode < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (& mut self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) { self . transform_children (| n , s | n . compile_network :: < D > (compile_env , s , nodes , clusters) , seen_tees ,) ; if let HfPlusNode :: Network { from_location , to_location , instantiate_fn , .. } = self { let (sink_expr , source_expr , connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { let ((sink , source) , connect_fn) = match (from_location , to_location) { (LocationId :: Process (from) , LocationId :: Process (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: o2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Process (from) , LocationId :: Cluster (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: o2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Process (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: m2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Cluster (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: m2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } } ; (sink , source , connect_fn) } DebugInstantiate :: Finalized (_ , _ , _) => panic ! ("network already finalized") , } ; * instantiate_fn = DebugInstantiate :: Finalized (sink_expr , source_expr , connect_fn) ; } } pub fn connect_network (& mut self , seen_tees : & mut SeenTees < 'a >) { self . transform_children (| n , s | n . connect_network (s) , seen_tees) ; if let HfPlusNode :: Network { instantiate_fn , .. } = self { match instantiate_fn { DebugInstantiate :: Building () => panic ! ("network not built") , DebugInstantiate :: Finalized (_ , _ , ref connect_fn) => { connect_fn () ; } } } } pub fn transform_children (& mut self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) { match self { HfPlusNode :: Placeholder => { panic ! () ; } HfPlusNode :: Source { .. } => { } HfPlusNode :: CycleSource { .. } => { } HfPlusNode :: Tee { inner } => { if let Some (transformed) = seen_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { * inner = transformed . clone () ; } else { let transformed_cell = Rc :: new (RefCell :: new (HfPlusNode :: Placeholder)) ; seen_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , transformed_cell . clone () ,) ; let mut orig = inner . replace (HfPlusNode :: Placeholder) ; transform (& mut orig , seen_tees) ; * transformed_cell . borrow_mut () = orig ; * inner = transformed_cell ; } } HfPlusNode :: Persist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Unpersist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Delta (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Union (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossProduct (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossSingleton (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Join (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Difference (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: AntiJoin (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Map { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FlatMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Filter { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FilterMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Sort (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: DeferTick (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Enumerate (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Inspect { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Unique (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Fold { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FoldKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Reduce { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: ReduceKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Network { input , .. } => { transform (input . as_mut () , seen_tees) ; } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) -> (syn :: Ident , usize) { match self { HfPlusNode :: Placeholder => { panic ! () } HfPlusNode :: Persist (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let persist_id = * next_stmt_id ; * next_stmt_id += 1 ; let persist_ident = syn :: Ident :: new (& format ! ("stream_{}" , persist_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # persist_ident = # inner_ident -> persist ::<'static > () ; }) ; (persist_ident , location) } HfPlusNode :: Unpersist (_) => { panic ! ("Unpersist is a marker node and should have been optimized away. This is likely a compiler bug.") } HfPlusNode :: Delta (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let delta_id = * next_stmt_id ; * next_stmt_id += 1 ; let delta_ident = syn :: Ident :: new (& format ! ("stream_{}" , delta_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # delta_ident = # inner_ident -> multiset_delta () ; }) ; (delta_ident , location) } HfPlusNode :: Source { source , location_kind , } => { let source_id = * next_stmt_id ; * next_stmt_id += 1 ; let source_ident = syn :: Ident :: new (& format ! ("stream_{}" , source_id) , Span :: call_site ()) ; let source_stmt = match source { HfPlusSource :: Stream (expr) => { parse_quote ! { # source_ident = source_stream (# expr) ; } } HfPlusSource :: Iter (expr) => { parse_quote ! { # source_ident = source_iter (# expr) ; } } HfPlusSource :: Interval (expr) => { parse_quote ! { # source_ident = source_interval (# expr) ; } } HfPlusSource :: Spin () => { parse_quote ! { # source_ident = spin () ; } } } ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; graph_builders . entry (* location_id) . or_default () . add_statement (source_stmt) ; (source_ident , * location_id) } HfPlusNode :: CycleSource { ident , location_kind , } => { let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; (ident . clone () , * location_id) } HfPlusNode :: Tee { inner } => { if let Some (ret) = built_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { ret . clone () } else { let (inner_ident , inner_location_id) = inner . borrow () . emit (graph_builders , built_tees , next_stmt_id) ; let tee_id = * next_stmt_id ; * next_stmt_id += 1 ; let tee_ident = syn :: Ident :: new (& format ! ("stream_{}" , tee_id) , Span :: call_site ()) ; let builder = graph_builders . entry (inner_location_id) . or_default () ; builder . add_statement (parse_quote ! { # tee_ident = # inner_ident -> tee () ; }) ; built_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , (tee_ident . clone () , inner_location_id) ,) ; (tee_ident , inner_location_id) } } HfPlusNode :: Union (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "union inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let union_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # union_ident = union () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [0] # union_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # union_ident ; }) ; (union_ident , left_location_id) } HfPlusNode :: CrossSingleton (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "cross_singleton inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let cross_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # cross_ident = cross_singleton () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [input] # cross_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [single] # cross_ident ; }) ; (cross_ident , left_location_id) } HfPlusNode :: CrossProduct (..) | HfPlusNode :: Join (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: CrossProduct (..)) { parse_quote ! (cross_join_multiset) } else { parse_quote ! (join_multiset) } ; let (HfPlusNode :: CrossProduct (left , right) | HfPlusNode :: Join (left , right)) = self else { unreachable ! () } ; let (left_inner , left_was_persist) = if let HfPlusNode :: Persist (left) = left . as_ref () { (left , true) } else { (left , false) } ; let (right_inner , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left_inner . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right_inner . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "join / cross product inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; match (left_was_persist , right_was_persist) { (true , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'static > () ; }) ; } (true , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'tick > () ; }) ; } (false , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } (false , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } } ; builder . add_statement (parse_quote ! { # left_ident -> [0] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Difference (..) | HfPlusNode :: AntiJoin (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Difference (..)) { parse_quote ! (difference_multiset) } else { parse_quote ! (anti_join_multiset) } ; let (HfPlusNode :: Difference (left , right) | HfPlusNode :: AntiJoin (left , right)) = self else { unreachable ! () } ; let (right , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "difference / anti join inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; if right_was_persist { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } else { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } builder . add_statement (parse_quote ! { # left_ident -> [pos] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [neg] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Map { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let map_id = * next_stmt_id ; * next_stmt_id += 1 ; let map_ident = syn :: Ident :: new (& format ! ("stream_{}" , map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # map_ident = # input_ident -> map (# f) ; }) ; (map_ident , input_location_id) } HfPlusNode :: FlatMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let flat_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let flat_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , flat_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # flat_map_ident = # input_ident -> flat_map (# f) ; }) ; (flat_map_ident , input_location_id) } HfPlusNode :: Filter { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_ident = # input_ident -> filter (# f) ; }) ; (filter_ident , input_location_id) } HfPlusNode :: FilterMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_map_ident = # input_ident -> filter_map (# f) ; }) ; (filter_map_ident , input_location_id) } HfPlusNode :: Sort (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sort_id = * next_stmt_id ; * next_stmt_id += 1 ; let sort_ident = syn :: Ident :: new (& format ! ("stream_{}" , sort_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # sort_ident = # input_ident -> sort () ; }) ; (sort_ident , input_location_id) } HfPlusNode :: DeferTick (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let defer_tick_id = * next_stmt_id ; * next_stmt_id += 1 ; let defer_tick_ident = syn :: Ident :: new (& format ! ("stream_{}" , defer_tick_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # defer_tick_ident = # input_ident -> defer_tick_lazy () ; }) ; (defer_tick_ident , input_location_id) } HfPlusNode :: Enumerate (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let enumerate_id = * next_stmt_id ; * next_stmt_id += 1 ; let enumerate_ident = syn :: Ident :: new (& format ! ("stream_{}" , enumerate_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # enumerate_ident = # input_ident -> enumerate () ; }) ; (enumerate_ident , input_location_id) } HfPlusNode :: Inspect { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let inspect_id = * next_stmt_id ; * next_stmt_id += 1 ; let inspect_ident = syn :: Ident :: new (& format ! ("stream_{}" , inspect_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # inspect_ident = # input_ident -> inspect (# f) ; }) ; (inspect_ident , input_location_id) } HfPlusNode :: Unique (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let unique_id = * next_stmt_id ; * next_stmt_id += 1 ; let unique_ident = syn :: Ident :: new (& format ! ("stream_{}" , unique_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # unique_ident = # input_ident -> unique ::<'tick > () ; }) ; (unique_ident , input_location_id) } HfPlusNode :: Fold { .. } | HfPlusNode :: FoldKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Fold { .. }) { parse_quote ! (fold) } else { parse_quote ! (fold_keyed) } ; let (HfPlusNode :: Fold { init , acc , input } | HfPlusNode :: FoldKeyed { init , acc , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let fold_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'static > (# init , # acc) ; }) ; } else { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'tick > (# init , # acc) ; }) ; } (fold_ident , input_location_id) } HfPlusNode :: Reduce { .. } | HfPlusNode :: ReduceKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Reduce { .. }) { parse_quote ! (reduce) } else { parse_quote ! (reduce_keyed) } ; let (HfPlusNode :: Reduce { f , input } | HfPlusNode :: ReduceKeyed { f , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let reduce_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'static > (# f) ; }) ; } else { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'tick > (# f) ; }) ; } (reduce_ident , input_location_id) } HfPlusNode :: Network { from_location : _ , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input , } => { let (sink_expr , source_expr , _connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { panic ! ("Expected the network to be finalized") } DebugInstantiate :: Finalized (sink , source , connect_fn) => { (sink , source , connect_fn) } } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sender_builder = graph_builders . entry (input_location_id) . or_default () ; if let Some (serialize_pipeline) = serialize_pipeline { sender_builder . add_statement (parse_quote ! { # input_ident -> # serialize_pipeline -> dest_sink (# sink_expr) ; }) ; } else { sender_builder . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink_expr) ; }) ; } let to_id = match to_location { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let receiver_builder = graph_builders . entry (* to_id) . or_default () ; let receiver_stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let receiver_stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , receiver_stream_id) , Span :: call_site ()) ; if let Some (deserialize_pipeline) = deserialize_pipeline { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) -> # deserialize_pipeline ; }) ; } else { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) ; }) ; } (receiver_stream_ident , * to_id) } } } } } pub mod persist_pullup { pub use std :: cell :: RefCell ; pub use std :: collections :: HashSet ; pub use std :: ops :: Deref ; pub use crate :: ir :: * ; pub fn persist_pullup_node < 'a > (node : & mut HfPlusNode < 'a > , seen_tees : & mut SeenTees < 'a > , persist_pulled_tees : & mut HashSet < * const RefCell < HfPlusNode < 'a > > > ,) { node . transform_children (| n , s | persist_pullup_node (n , s , persist_pulled_tees) , seen_tees ,) ; match node { HfPlusNode :: Unpersist (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Unpersist (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Delta (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Delta (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Tee { inner } => { if persist_pulled_tees . contains (& (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >)) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } else { let inner_borrow = inner . borrow () ; if let HfPlusNode :: Persist (_) = inner_borrow . deref () { drop (inner_borrow) ; persist_pulled_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >) ; if let HfPlusNode :: Persist (box behind_persist) = inner . replace (HfPlusNode :: Placeholder) { * inner . borrow_mut () = behind_persist ; } else { unreachable ! () } * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } } } HfPlusNode :: Map { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Map { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Map { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: FlatMap { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: FlatMap { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: FlatMap { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Filter { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Filter { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Filter { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Network { input : box HfPlusNode :: Persist (_) , .. } => { if let HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Union (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Union (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Union (left , right))) ; } else { unreachable ! () } } HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: CrossProduct (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,) ,)))) ; } else { unreachable ! () } } HfPlusNode :: Join (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Join (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: Join (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,))))) ; } else { unreachable ! () } } _ => { } } } pub fn persist_pullup (ir : Vec < HfPlusLeaf >) -> Vec < HfPlusLeaf > { let mut seen_tees = Default :: default () ; let mut persist_pulled_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| n , s | persist_pullup_node (n , s , & mut persist_pulled_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn persist_pullup_through_map () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } # [test] fn persist_pullup_behind_tee () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; let before_tee = flow . source_iter (& process , q ! (0 .. 10)) . tick_batch () . persist () ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } } } pub mod profiler { pub use std :: cell :: RefCell ; pub use hydroflow :: futures :: channel :: mpsc :: UnboundedSender ; pub use stageleft :: * ; pub use crate as hydroflow_plus ; pub use crate :: ir :: * ; pub use crate :: RuntimeContext ; pub fn increment_counter (count : & mut u64) { * count += 1 ; } pub fn quoted_any_fn < 'a , F : Fn (& usize) + 'a , Q : IntoQuotedMut < 'a , F > > (q : Q) -> Q { q } # [doc = " Add a profiling node before each node to count the cardinality of its input"] pub fn add_profiling_node < 'a > (node : & mut HfPlusNode < 'a > , _context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > , id : & mut u32 , seen_tees : & mut SeenTees < 'a > ,) { let my_id = * id ; * id += 1 ; node . transform_children (| node , seen_tees | { add_profiling_node (node , _context , counters , counter_queue , id , seen_tees) } , seen_tees ,) ; let orig_node = std :: mem :: replace (node , HfPlusNode :: Placeholder) ; * node = HfPlusNode :: Inspect { f : quoted_any_fn (q ! ({ counter_queue . borrow () . unbounded_send ((my_id as usize , counters . borrow () [my_id as usize])) . unwrap () ; counters . borrow_mut () [my_id as usize] = 0 ; move | _ | { hydroflow_plus :: profiler :: increment_counter (& mut counters . borrow_mut () [my_id as usize] ,) ; } })) . splice () . into () , input : Box :: new (orig_node) , } } # [doc = " Count the cardinality of each input and periodically output to a file"] pub fn profiling < 'a > (ir : Vec < HfPlusLeaf < 'a > > , context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > ,) -> Vec < HfPlusLeaf < 'a > > { let mut id = 0 ; let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | { add_profiling_node (node , context , counters , counter_queue , & mut id , seen_tees) } , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn profiler_wrapping_all_operators () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let runtime_context = flow . runtime_context () ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (& built . ir ()) ; let counters = RuntimeData :: new ("Fake") ; let counter_queue = RuntimeData :: new ("Fake") ; let pushed_down = built . with_default_optimize () . optimize_with (| ir | super :: profiling (ir , runtime_context , counters , counter_queue)) ; insta :: assert_debug_snapshot ! (& pushed_down . ir ()) ; let _ = pushed_down . compile_no_network :: < MultiGraph > () ; } } } pub mod properties { pub use std :: collections :: HashSet ; pub use stageleft :: * ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , SeenTees } ; pub use crate :: properties :: PropertyDatabase ; # [doc = " Allows us to convert the hydroflow datatype for folds to a binary operation for the algebra"] # [doc = " property tests."] # [allow (dead_code)] pub fn convert_hf_to_binary < I , A : Default , F : Fn (& mut A , I) > (f : F) -> impl Fn (I , I) -> A { move | a , b | { let mut acc = Default :: default () ; f (& mut acc , a) ; f (& mut acc , b) ; acc } } # [cfg (stageleft_macro)] impl PropertyDatabase { # [doc = " Tags the expression as commutative."] pub fn add_commutative_tag < 'a , I , A , F : Fn (& mut A , I) , Q : Quoted < 'a , F > + Clone > (& mut self , expr : Q ,) -> Q { let expr_clone = expr . clone () ; self . commutative . insert (expr_clone . splice ()) ; expr } pub fn is_tagged_commutative (& self , expr : & syn :: Expr) -> bool { self . commutative . contains (expr) } } pub fn properties_optimize_node < 'a > (node : & mut HfPlusNode < 'a > , db : & PropertyDatabase , seen_tees : & mut SeenTees < 'a > ,) { node . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , seen_tees ,) ; match node { HfPlusNode :: ReduceKeyed { f , .. } if db . is_tagged_commutative (& f . 0) => { dbg ! ("IDENTIFIED COMMUTATIVE OPTIMIZATION for {:?}" , & f) ; } _ => { } } } pub fn properties_optimize < 'a > (ir : Vec < HfPlusLeaf < 'a > > , db : & PropertyDatabase ,) -> Vec < HfPlusLeaf < 'a > > { let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use super :: * ; use crate :: deploy :: SingleProcessGraph ; use crate :: FlowBuilder ; # [test] fn test_property_database () { let mut db = PropertyDatabase :: default () ; assert ! (! db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; let _ = db . add_commutative_tag (q ! (| a : & mut i32 , b : i32 | * a += b)) ; assert ! (db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; } # [test] fn test_property_optimized () { let flow = FlowBuilder :: new () ; let mut database = PropertyDatabase :: default () ; let process = flow . process :: < () > () ; let counter_func = q ! (| count : & mut i32 , _ | * count += 1) ; let _ = database . add_commutative_tag (counter_func) ; flow . source_iter (& process , q ! (vec ! [])) . map (q ! (| string : String | (string , ()))) . tick_batch () . fold_keyed (q ! (|| 0) , counter_func) . all_ticks () . for_each (q ! (| (string , count) | println ! ("{}: {}" , string , count))) ; let built = flow . finalize () . optimize_with (| ir | properties_optimize (ir , & database)) . with_default_optimize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let _ = built . compile_no_network :: < SingleProcessGraph > () ; } } } pub use crate :: RuntimeContext ; # [cfg (stageleft_macro)] impl Copy for RuntimeContext < '_ > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Context > for RuntimeContext < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (quote ! (& context))) } } pub use crate :: HfCompiled ; # [cfg (stageleft_macro)] impl < 'a , ID > HfCompiled < 'a , ID > { pub fn hydroflow_ir (& self) -> & BTreeMap < usize , HydroflowGraph > { & self . hydroflow_ir } } # [cfg (stageleft_macro)] impl < 'a > HfCompiled < 'a , usize > { pub fn with_dynamic_id (self , id : impl Quoted < 'a , usize >) -> HfBuiltWithId < 'a > { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; let mut conditioned_tokens = None ; for (subgraph_id , flat_graph) in self . hydroflow_ir { let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; let my_extra_stmts = self . extra_stmts . get (& subgraph_id) . cloned () . unwrap_or_default () ; if let Some (conditioned_tokens) = conditioned_tokens . as_mut () { * conditioned_tokens = syn :: parse_quote ! { # conditioned_tokens else if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } } ; } else { conditioned_tokens = Some (syn :: parse_quote ! { if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } }) ; } } let conditioned_tokens : TokenStream = conditioned_tokens . unwrap () ; let id = id . splice () ; HfBuiltWithId { tokens : syn :: parse_quote ! ({ let __given_id = # id ; # conditioned_tokens else { panic ! ("Invalid node id: {}" , __given_id) ; } }) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfCompiled < 'a , () > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfCompiled < 'a , () > { fn to_tokens (mut self) -> (Option < TokenStream > , Option < TokenStream >) { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; if self . hydroflow_ir . len () != 1 { panic ! ("Expected exactly one subgraph in the Hydroflow IR") ; } let flat_graph = self . hydroflow_ir . remove (& 0) . unwrap () ; let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; (None , Some (tokens)) } } pub use crate :: HfBuiltWithId ; # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfBuiltWithId < 'a > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfBuiltWithId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (self . tokens)) } }
[INFO] [stdout] 1 + pub use std :: collections :: BTreeMap ; pub use std :: marker :: PhantomData ; pub use hydroflow :: scheduled :: context :: Context ; pub use hydroflow :: scheduled :: graph :: Hydroflow ; pub use hydroflow :: * ; pub use lang :: graph :: { partition_graph , HydroflowGraph } ; pub use proc_macro2 :: TokenStream ; pub use quote :: quote ; pub use stageleft :: runtime_support :: FreeVariable ; pub use stageleft :: Quoted ; pub mod runtime_support { pub use bincode ; } pub mod stream { pub use std :: cell :: RefCell ; pub use std :: hash :: Hash ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow :: bytes :: Bytes ; pub use hydroflow :: futures :: Sink ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: quote ; pub use serde :: de :: DeserializeOwned ; pub use serde :: Serialize ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use syn :: parse_quote ; pub use crate :: builder :: { ClusterIds , FlowLeaves } ; pub use crate :: cycle :: { CycleCollection , CycleComplete } ; pub use crate :: ir :: { DebugInstantiate , HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { CanSend , Location , LocationId } ; pub use crate :: { Cluster , Optional , Singleton } ; pub use crate :: stream :: Unbounded ; pub use crate :: stream :: Bounded ; pub use crate :: stream :: NoTick ; pub use crate :: stream :: Tick ; pub use crate :: stream :: Stream ; # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Stream { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Stream < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Stream { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , C , N > > ,) -> Stream < 'a , (T , O) , W , C , N > where O : Clone , { let other : Optional < 'a , O , Bounded , C , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn cross_product < O > (self , other : Stream < 'a , O , W , C , N >) -> Stream < 'a , (T , O) , W , C , N > where T : Clone , O : Clone , { if self . location_kind != other . location_kind { panic ! ("cross_product must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossProduct (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn union (self , other : Stream < 'a , T , W , C , N >) -> Stream < 'a , T , W , C , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn dest_sink < S : Unpin + Sink < T > + 'a > (self , sink : impl Quoted < 'a , S >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: DestSink { sink : sink . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn first (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } # [doc = " Allow this stream through if the other stream has elements, otherwise the output is empty."] pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } # [doc = " Allow this stream through if the other stream is empty, otherwise the output is empty."] pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn enumerate (self) -> Stream < 'a , (usize , T) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Enumerate (Box :: new (self . ir_node . into_inner ())) ,) } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn sort (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Ord , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Sort (Box :: new (self . ir_node . into_inner ())) ,) } pub fn count (self) -> Singleton < 'a , usize , Bounded , Tick , N > { self . fold (q ! (|| 0usize) , q ! (| count , _ | * count += 1)) } pub fn delta (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } pub fn unique (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Eq + Hash , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unique (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn tick_batch (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_prefix (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { self . tick_batch () . persist () } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn for_each < F : Fn (T) + 'a > (self , f : impl IntoQuotedMut < 'a , F >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: ForEach { input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , f : f . splice () . into () , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Unbounded , NoTick , N > { pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . tick_batch () . continue_if (samples . first ()) . all_ticks () } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Unbounded , NoTick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , C , N : Location > Stream < 'a , T , Bounded , C , N > { pub fn filter_not_in (self , other : Stream < 'a , T , Bounded , C , N >) -> Stream < 'a , T , Bounded , C , N > where T : Eq + Hash , { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Difference (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Stream < 'a , & T , W , C , N > { pub fn cloned (self) -> Stream < 'a , T , W , C , N > { self . map (q ! (| d | d . clone ())) } } # [cfg (stageleft_macro)] impl < 'a , K , V1 , W , C , N : Location > Stream < 'a , (K , V1) , W , C , N > { pub fn join < W2 , V2 > (self , n : Stream < 'a , (K , V2) , W2 , C , N > ,) -> Stream < 'a , (K , (V1 , V2)) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Join (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } pub fn anti_join < W2 > (self , n : Stream < 'a , K , W2 , C , N >) -> Stream < 'a , (K , V1) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("anti_join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: AntiJoin (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , K : Eq + Hash , V , N : Location > Stream < 'a , (K , V) , Bounded , Tick , N > { pub fn fold_keyed < A , I : Fn () -> A + 'a , F : Fn (& mut A , V) + 'a > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , A) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FoldKeyed { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce_keyed < F : Fn (& mut V , V) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , V) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: ReduceKeyed { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } pub fn get_this_crate () -> TokenStream { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , Span :: call_site ()) ; quote ! { # ident } } } } pub fn serialize_bincode < T : Serialize > (is_demux : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if is_demux { parse_quote ! { map (| (id , data) | { (id , # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into ()) }) } } else { parse_quote ! { map (| data | { # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into () }) } } } pub fn deserialize_bincode < T : DeserializeOwned > (tagged : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if tagged { parse_quote ! { map (| res | { let (id , b) = res . unwrap () ; (id , # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& b) . unwrap ()) }) } } else { parse_quote ! { map (| res | { # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& res . unwrap ()) . unwrap () }) } } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn send_bincode < N2 : Location , CoreType > (self , other : & N2 ,) -> Stream < 'a , N :: Out < CoreType > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T > , CoreType : Serialize + DeserializeOwned , { let serialize_pipeline = Some (serialize_bincode :: < CoreType > (N :: is_demux ())) ; let deserialize_pipeline = Some (deserialize_bincode :: < CoreType > (N :: is_tagged ())) ; Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bytes < N2 : Location > (self , other : & N2 ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T > , { Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline : None , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline : if N :: is_tagged () { Some (parse_quote ! (map (| (id , b) | (id , b . unwrap () . freeze ())))) } else { Some (parse_quote ! (map (| b | b . unwrap () . freeze ()))) } , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bincode_interleaved < N2 : Location , Tag , CoreType > (self , other : & N2 ,) -> Stream < 'a , CoreType , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T , Out < CoreType > = (Tag , CoreType) > , CoreType : Serialize + DeserializeOwned , { self . send_bincode :: < N2 , CoreType > (other) . map (q ! (| (_ , b) | b)) } pub fn send_bytes_interleaved < N2 : Location , Tag > (self , other : & N2 ,) -> Stream < 'a , Bytes , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T , Out < Bytes > = (Tag , Bytes) > , { self . send_bytes :: < N2 > (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bincode < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < T > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) > , T : Clone + Serialize + DeserializeOwned , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bincode (other) } pub fn broadcast_bincode_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , T , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) , Out < T > = (Tag , T) > + 'a , T : Clone + Serialize + DeserializeOwned , { self . broadcast_bincode (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bytes < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) > + 'a , T : Clone , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bytes (other) } pub fn broadcast_bytes_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , Bytes , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) , Out < Bytes > = (Tag , Bytes) > + 'a , T : Clone , { self . broadcast_bytes (other) . map (q ! (| (_ , b) | b)) } } } pub use stream :: { Bounded , NoTick , Stream , Tick , Unbounded } ; pub mod singleton { pub use std :: cell :: RefCell ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use crate :: builder :: FlowLeaves ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial , CycleComplete } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: Stream ; pub use crate :: singleton :: CrossResult ; # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Singleton < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Singleton :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } pub use crate :: singleton :: Singleton ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Singleton { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleComplete < 'a > for Singleton < 'a , T , Bounded , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleCollectionWithInitial < 'a > for Singleton < 'a , T , Bounded , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , initial : Self , l : LocationId ,) -> Self { Singleton :: new (l , ir_leaves , HfPlusNode :: Union (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , }) , initial . ir_node . into_inner () . into () ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Singleton < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Singleton { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , U , W , C , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (Self :: other_ir_node (other)) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Singleton < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CrossSingleton (Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , Box :: new (HfPlusNode :: Unpersist (Box :: new (Self :: other_ir_node (other)))) ,))) ,) } } pub use crate :: singleton :: Optional ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Optional { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } pub fn some (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: new (singleton . location_kind , singleton . ir_leaves , singleton . ir_node . into_inner () ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > From < Singleton < 'a , T , W , C , N > > for Optional < 'a , T , W , C , N > { fn from (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: some (singleton) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Optional < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Optional { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn into_stream (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , Tick , N > > ,) -> Optional < 'a , (T , O) , Bounded , Tick , N > where O : Clone , { let other : Optional < 'a , O , Bounded , Tick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn union (self , other : Optional < 'a , T , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Optional < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_samples (self) -> Stream < 'a , T , Unbounded , NoTick , N > { self . latest_tick () . all_ticks () } pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . latest_tick () . continue_if (samples . first ()) . latest () . tick_samples () } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Unbounded , NoTick , N > > ,) -> Optional < 'a , (T , O) , Unbounded , NoTick , N > where O : Clone , { let other : Optional < 'a , O , Unbounded , NoTick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } self . latest_tick () . cross_singleton (other . latest_tick ()) . latest () } } } pub use singleton :: { Optional , Singleton } ; pub mod location { pub use std :: marker :: PhantomData ; pub use crate :: location :: LocationId ; pub use crate :: location :: Location ; pub use crate :: location :: Process ; # [cfg (stageleft_macro)] impl < P > Clone for Process < P > { fn clone (& self) -> Self { Process { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < P > Location for Process < P > { fn id (& self) -> LocationId { LocationId :: Process (self . id) } } pub use crate :: location :: Cluster ; # [cfg (stageleft_macro)] impl < C > Clone for Cluster < C > { fn clone (& self) -> Self { Cluster { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < C > Location for Cluster < C > { fn id (& self) -> LocationId { LocationId :: Cluster (self . id) } } pub use crate :: location :: CanSend ; # [cfg (stageleft_macro)] impl < P1 , P2 > CanSend < Process < P2 > > for Process < P1 > { type In < T > = T ; type Out < T > = T ; fn is_demux () -> bool { false } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < P1 , C2 > CanSend < Cluster < C2 > > for Process < P1 > { type In < T > = (u32 , T) ; type Out < T > = T ; fn is_demux () -> bool { true } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < C1 , P2 > CanSend < Process < P2 > > for Cluster < C1 > { type In < T > = T ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { false } fn is_tagged () -> bool { true } } # [cfg (stageleft_macro)] impl < C1 , C2 > CanSend < Cluster < C2 > > for Cluster < C1 > { type In < T > = (u32 , T) ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { true } fn is_tagged () -> bool { true } } } pub use location :: { Cluster , Process } ; pub mod deploy { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use stageleft :: Quoted ; pub mod graphs { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use super :: { LocalDeploy , Node , ProcessSpec } ; pub use crate :: deploy :: graphs :: SingleProcessGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for SingleProcessGraph { type Process = SingleNode ; type Cluster = SingleNode ; type Meta = () ; type GraphId = () ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { SingleNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { SingleNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , SingleProcessGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> SingleNode { SingleNode { } } } pub use crate :: deploy :: graphs :: SingleNode ; # [cfg (stageleft_macro)] impl Node for SingleNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } pub use crate :: deploy :: graphs :: MultiGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for MultiGraph { type Process = MultiNode ; type Cluster = MultiNode ; type Meta = () ; type GraphId = usize ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { MultiNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { MultiNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , MultiGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> MultiNode { MultiNode { } } } pub use crate :: deploy :: graphs :: MultiNode ; # [cfg (stageleft_macro)] impl Node for MultiNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } } pub use graphs :: * ; pub use crate :: deploy :: LocalDeploy ; pub use crate :: deploy :: Deploy ; # [cfg (stageleft_macro)] impl < 'a , T : Deploy < 'a , Process = N , Cluster = C , Meta = M , GraphId = R > , N : Node < Meta = M > , C : Node < Meta = M > , M : Default , R , > LocalDeploy < 'a > for T { type Process = N ; type Cluster = C ; type Meta = M ; type GraphId = R ; fn has_trivial_node () -> bool { < T as Deploy < 'a > > :: has_trivial_node () } fn trivial_process (id : usize) -> Self :: Process { < T as Deploy < 'a > > :: trivial_process (id) } fn trivial_cluster (id : usize) -> Self :: Cluster { < T as Deploy < 'a > > :: trivail_cluster (id) } } pub use crate :: deploy :: ProcessSpec ; pub use crate :: deploy :: ClusterSpec ; pub use crate :: deploy :: Node ; } pub use deploy :: { ClusterSpec , Deploy , ProcessSpec } ; pub mod cycle { pub use std :: marker :: PhantomData ; pub use crate :: builder :: FlowLeaves ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: cycle :: CycleComplete ; pub use crate :: cycle :: CycleCollection ; pub use crate :: cycle :: CycleCollectionWithInitial ; pub use crate :: cycle :: HfCycle ; # [cfg (stageleft_macro)] impl < 'a , S : CycleComplete < 'a > > HfCycle < 'a , S > { pub fn complete (self , stream : S) { let ident = self . ident ; S :: complete (stream , ident) } } } pub use cycle :: HfCycle ; pub mod builder { pub use std :: cell :: RefCell ; pub use std :: collections :: HashMap ; pub use std :: marker :: PhantomData ; pub use std :: rc :: Rc ; pub use std :: time :: Duration ; pub use hydroflow :: futures :: stream :: Stream as FuturesStream ; pub use hydroflow :: { tokio , tokio_stream } ; pub use internal :: TokenStream ; pub use proc_macro2 :: Span ; pub use quote :: quote ; pub use runtime_support :: FreeVariable ; pub use stageleft :: * ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Cluster , Location , LocationId , Process } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: { HfCycle , Optional , RuntimeContext , Singleton , Stream } ; pub mod built { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use hydroflow_lang :: graph :: { eliminate_extra_unions_tees , HydroflowGraph } ; pub use super :: deploy :: { DeployFlow , DeployResult } ; pub use crate :: deploy :: { ClusterSpec , Deploy , LocalDeploy , ProcessSpec } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Cluster , Process } ; pub use crate :: HfCompiled ; pub use crate :: builder :: built :: BuiltFlow ; # [cfg (stageleft_macro)] impl < 'a > Drop for BuiltFlow < 'a > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped BuiltFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn ir (& self) -> & Vec < HfPlusLeaf < 'a > > { & self . ir } pub fn optimize_with (mut self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> BuiltFlow < 'a > { self . used = true ; BuiltFlow { ir : f (std :: mem :: take (& mut self . ir)) , processes : std :: mem :: take (& mut self . processes) , clusters : std :: mem :: take (& mut self . clusters) , used : false , _phantom : PhantomData , } } } pub fn build_inner (ir : & mut Vec < HfPlusLeaf >) -> BTreeMap < usize , HydroflowGraph > { let mut builders = BTreeMap :: new () ; let mut built_tees = HashMap :: new () ; let mut next_stmt_id = 0 ; for leaf in ir { leaf . emit (& mut builders , & mut built_tees , & mut next_stmt_id) ; } builders . into_iter () . map (| (k , v) | { let (mut flat_graph , _ , _) = v . build () ; eliminate_extra_unions_tees (& mut flat_graph) ; (k , flat_graph) }) . collect () } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn compile_no_network < D : LocalDeploy < 'a > > (mut self) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; HfCompiled { hydroflow_ir : build_inner (& mut self . ir) , extra_stmts : BTreeMap :: new () , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> BuiltFlow < 'a > { self . optimize_with (crate :: persist_pullup :: persist_pullup) } fn into_deploy < D : LocalDeploy < 'a > > (mut self) -> DeployFlow < 'a , D > { self . used = true ; let processes = if D :: has_trivial_node () { self . processes . iter () . map (| id | (* id , D :: trivial_process (* id))) . collect () } else { HashMap :: new () } ; let clusters = if D :: has_trivial_node () { self . clusters . iter () . map (| id | (* id , D :: trivial_cluster (* id))) . collect () } else { HashMap :: new () } ; DeployFlow { ir : std :: mem :: take (& mut self . ir) , nodes : processes , clusters , used : false , _phantom : PhantomData , } } pub fn with_process < P , D : LocalDeploy < 'a > > (self , process : & Process < P > , spec : impl ProcessSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_process (process , spec) } pub fn with_cluster < C , D : LocalDeploy < 'a > > (self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_cluster (cluster , spec) } pub fn compile < D : Deploy < 'a > + 'a > (self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . into_deploy :: < D > () . compile (env) } pub fn deploy < D : Deploy < 'a , CompileEnv = () > + 'a > (self , env : & mut D :: InstantiateEnv ,) -> DeployResult < 'a , D > { self . into_deploy :: < D > () . deploy (env) } } } pub mod deploy { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use proc_macro2 :: Span ; pub use stageleft :: Quoted ; pub use super :: built :: build_inner ; pub use crate :: deploy :: { LocalDeploy , Node } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: { Cluster , ClusterSpec , Deploy , HfCompiled , Process , ProcessSpec } ; pub use crate :: builder :: deploy :: DeployFlow ; # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > Drop for DeployFlow < 'a , D > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped DeployFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > DeployFlow < 'a , D > { pub fn with_process < P > (mut self , process : & Process < P > , spec : impl ProcessSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < P > () . to_string () ; self . nodes . insert (process . id , spec . build (process . id , & tag_name)) ; self } pub fn with_cluster < C > (mut self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < C > () . to_string () ; self . clusters . insert (cluster . id , spec . build (cluster . id , & tag_name)) ; self } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployFlow < 'a , D > { pub fn compile (mut self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; let mut seen_tees : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | leaf . compile_network :: < D > (env , & mut seen_tees , & self . nodes , & self . clusters)) . collect () ; let extra_stmts = self . extra_stmts (env) ; HfCompiled { hydroflow_ir : build_inner (& mut ir_leaves_networked) , extra_stmts , _phantom : PhantomData , } } fn extra_stmts (& self , env : & < D as Deploy < 'a > > :: CompileEnv) -> BTreeMap < usize , Vec < syn :: Stmt > > { let all_locations_count = self . nodes . len () + self . clusters . len () ; let mut extra_stmts : BTreeMap < usize , Vec < syn :: Stmt > > = BTreeMap :: new () ; for & c_id in self . clusters . keys () { let self_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , c_id) , Span :: call_site () ,) ; let self_id_expr = D :: cluster_self_id (env) . splice () ; extra_stmts . entry (c_id) . or_default () . push (syn :: parse_quote ! { let # self_id_ident = # self_id_expr ; }) ; for other_location in 0 .. all_locations_count { let other_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , c_id) , Span :: call_site () ,) ; let other_id_expr = D :: cluster_ids (env , c_id) . splice () ; extra_stmts . entry (other_location) . or_default () . push (syn :: parse_quote ! { let # other_id_ident = # other_id_expr ; }) ; } } extra_stmts } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a , CompileEnv = () > > DeployFlow < 'a , D > { # [must_use] pub fn deploy (mut self , env : & mut D :: InstantiateEnv) -> DeployResult < 'a , D > { self . used = true ; let mut seen_tees_instantiate : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | { leaf . compile_network :: < D > (& () , & mut seen_tees_instantiate , & self . nodes , & self . clusters ,) }) . collect () ; let mut compiled = build_inner (& mut ir_leaves_networked) ; let mut extra_stmts = self . extra_stmts (& ()) ; let mut meta = D :: Meta :: default () ; let (mut processes , mut clusters) = (std :: mem :: take (& mut self . nodes) . into_iter () . map (| (node_id , node) | { node . instantiate (env , & mut meta , compiled . remove (& node_id) . unwrap () , extra_stmts . remove (& node_id) . unwrap_or_default () ,) ; (node_id , node) }) . collect :: < HashMap < _ , _ > > () , std :: mem :: take (& mut self . clusters) . into_iter () . map (| (cluster_id , cluster) | { cluster . instantiate (env , & mut meta , compiled . remove (& cluster_id) . unwrap () , extra_stmts . remove (& cluster_id) . unwrap_or_default () ,) ; (cluster_id , cluster) }) . collect :: < HashMap < _ , _ > > () ,) ; for node in processes . values_mut () { node . update_meta (& meta) ; } for cluster in clusters . values_mut () { cluster . update_meta (& meta) ; } let mut seen_tees_connect = HashMap :: new () ; for leaf in ir_leaves_networked { leaf . connect_network (& mut seen_tees_connect) ; } DeployResult { processes , clusters , } } } pub use crate :: builder :: deploy :: DeployResult ; # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployResult < 'a , D > { pub fn get_process < P > (& self , p : & Process < P >) -> & D :: Process { let id = match p . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . processes . get (& id) . unwrap () } pub fn get_cluster < C > (& self , c : & Cluster < C >) -> & D :: Cluster { let id = match c . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . clusters . get (& id) . unwrap () } } } # [doc = " Tracks the leaves of the dataflow IR. This is referenced by"] # [doc = " `Stream` and `HfCycle` to build the IR. The inner option will"] # [doc = " be set to `None` when this builder is finalized."] pub type FlowLeaves < 'a > = Rc < RefCell < Option < Vec < HfPlusLeaf < 'a > > > > > ; pub use crate :: builder :: ClusterIds ; # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Vec < u32 > > for ClusterIds < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , & 'a Vec < u32 > > for ClusterIds < 'a > { } # [derive (Copy , Clone)] pub struct ClusterSelfId < 'a > { pub id : usize , pub _phantom : PhantomData < & 'a mut & 'a u32 > , } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < u32 > for ClusterSelfId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , u32 > for ClusterSelfId < 'a > { } pub use crate :: builder :: FlowBuilder ; # [cfg (stageleft_macro)] impl < 'a > Drop for FlowBuilder < 'a > { fn drop (& mut self) { if ! self . finalized { panic ! ("Dropped FlowBuilder without finalizing, you may have forgotten to call `with_default_optimize`, `optimize_with`, or `finalize`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > QuotedContext for FlowBuilder < 'a > { fn create () -> Self { FlowBuilder :: new () } } # [cfg (stageleft_macro)] impl < 'a > FlowBuilder < 'a > { # [allow (clippy :: new_without_default)] pub fn new () -> FlowBuilder < 'a > { FlowBuilder { ir_leaves : Rc :: new (RefCell :: new (Some (Vec :: new ()))) , nodes : RefCell :: new (vec ! []) , clusters : RefCell :: new (vec ! []) , cycle_ids : RefCell :: new (HashMap :: new ()) , next_node_id : RefCell :: new (0) , finalized : false , _phantom : PhantomData , } } pub fn finalize (mut self) -> built :: BuiltFlow < 'a > { self . finalized = true ; built :: BuiltFlow { ir : self . ir_leaves . borrow_mut () . take () . unwrap () , processes : self . nodes . replace (vec ! []) , clusters : self . clusters . replace (vec ! []) , used : false , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> built :: BuiltFlow < 'a > { self . finalize () . with_default_optimize () } pub fn optimize_with (self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> built :: BuiltFlow < 'a > { self . finalize () . optimize_with (f) } pub fn ir_leaves (& self) -> & FlowLeaves < 'a > { & self . ir_leaves } pub fn process < P > (& self) -> Process < P > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . nodes . borrow_mut () . push (id) ; Process { id , _phantom : PhantomData , } } pub fn cluster < C > (& self) -> Cluster < C > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . clusters . borrow_mut () . push (id) ; Cluster { id , _phantom : PhantomData , } } pub fn runtime_context (& self) -> RuntimeContext < 'a > { RuntimeContext { _phantom : PhantomData , } } pub fn cluster_members < C > (& self , cluster : & Cluster < C > ,) -> impl Quoted < 'a , & 'a Vec < u32 > > + Copy + 'a { ClusterIds { id : cluster . id , _phantom : PhantomData , } } pub fn cluster_self_id < C > (& self , cluster : & Cluster < C >) -> impl Quoted < 'a , u32 > + Copy + 'a { ClusterSelfId { id : cluster . id , _phantom : PhantomData , } } pub fn spin < L : Location > (& self , on : & L) -> Stream < 'a , () , Unbounded , NoTick , L > { Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Spin () , location_kind : on . id () , })) ,) } pub fn spin_batch < L : Location > (& self , on : & L , batch_size : impl Quoted < 'a , usize > + Copy + 'a ,) -> Stream < 'a , () , Bounded , Tick , L > { self . spin (on) . flat_map (q ! (move | _ | 0 .. batch_size)) . map (q ! (| _ | ())) . tick_batch () } pub fn source_stream < T , E : FuturesStream < Item = T > + Unpin , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Unbounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Stream (e . into ()) , location_kind : on . id () , })) ,) } pub fn source_iter < T , E : IntoIterator < Item = T > , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Bounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , })) ,) } pub fn singleton < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Singleton < 'a , T , Bounded , NoTick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Singleton :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,)))) ,) } pub fn singleton_first_tick < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Optional < 'a , T , Bounded , Tick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,) } pub fn source_interval < L : Location > (& self , on : & L , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , () , Unbounded , NoTick , L > { let interval = interval . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : on . id () , })) ,) } pub fn source_interval_delayed < L : Location > (& self , on : & L , delay : impl Quoted < 'a , Duration > + Copy + 'a , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , tokio :: time :: Instant , Unbounded , NoTick , L > { self . source_stream (on , q ! (tokio_stream :: wrappers :: IntervalStream :: new (tokio :: time :: interval_at (tokio :: time :: Instant :: now () + delay , interval))) ,) . tick_batch () . first () . latest () } pub fn cycle < S : CycleCollection < 'a > > (& self , on : & S :: Location) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , on . id ()) ,) } pub fn cycle_with_initial < S : CycleCollectionWithInitial < 'a > > (& self , on : & S :: Location , initial : S ,) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , initial , on . id ()) ,) } } } pub use builder :: FlowBuilder ; pub mod ir { pub use core :: panic ; pub use std :: cell :: RefCell ; pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow_lang :: graph :: FlatGraphBuilder ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: ToTokens ; pub use syn :: parse_quote ; pub use crate :: deploy :: Deploy ; pub use crate :: location :: LocationId ; pub use crate :: ir :: DebugExpr ; # [cfg (stageleft_macro)] impl From < syn :: Expr > for DebugExpr { fn from (expr : syn :: Expr) -> DebugExpr { DebugExpr (expr) } } # [cfg (stageleft_macro)] impl Deref for DebugExpr { type Target = syn :: Expr ; fn deref (& self) -> & Self :: Target { & self . 0 } } # [cfg (stageleft_macro)] impl ToTokens for DebugExpr { fn to_tokens (& self , tokens : & mut TokenStream) { self . 0 . to_tokens (tokens) ; } } # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugExpr { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "{}" , self . 0 . to_token_stream ()) } } pub use crate :: ir :: DebugInstantiate ; # [cfg (stageleft_macro)] impl < 'a > std :: fmt :: Debug for DebugInstantiate < 'a > { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<network instantiate>") } } pub use crate :: ir :: DebugPipelineFn ; # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugPipelineFn { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<function>") } } pub use crate :: ir :: HfPlusSource ; pub use crate :: ir :: HfPlusLeaf ; # [cfg (stageleft_macro)] impl < 'a > HfPlusLeaf < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . compile_network :: < D > (compile_env , s , nodes , clusters) ; } , seen_tees ,) } pub fn connect_network (self , seen_tees : & mut SeenTees < 'a >) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . connect_network (s) ; } , seen_tees ,) } pub fn transform_children (self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) -> HfPlusLeaf < 'a > { match self { HfPlusLeaf :: ForEach { f , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: ForEach { f , input } } HfPlusLeaf :: DestSink { sink , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: DestSink { sink , input } } HfPlusLeaf :: CycleSink { ident , location_kind , mut input , } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: CycleSink { ident , location_kind , input , } } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) { match self { HfPlusLeaf :: ForEach { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> for_each (# f) ; }) ; } HfPlusLeaf :: DestSink { sink , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink) ; }) ; } HfPlusLeaf :: CycleSink { ident , location_kind , input , } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; assert_eq ! (input_location_id , * location_id , "cycle_sink location mismatch") ; graph_builders . entry (* location_id) . or_default () . add_statement (parse_quote ! { # ident = # input_ident ; }) ; } } } } pub use crate :: ir :: HfPlusNode ; pub type SeenTees < 'a > = HashMap < * const RefCell < HfPlusNode < 'a > > , Rc < RefCell < HfPlusNode < 'a > > > > ; # [cfg (stageleft_macro)] impl < 'a > HfPlusNode < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (& mut self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) { self . transform_children (| n , s | n . compile_network :: < D > (compile_env , s , nodes , clusters) , seen_tees ,) ; if let HfPlusNode :: Network { from_location , to_location , instantiate_fn , .. } = self { let (sink_expr , source_expr , connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { let ((sink , source) , connect_fn) = match (from_location , to_location) { (LocationId :: Process (from) , LocationId :: Process (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: o2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Process (from) , LocationId :: Cluster (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: o2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Process (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: m2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Cluster (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: m2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } } ; (sink , source , connect_fn) } DebugInstantiate :: Finalized (_ , _ , _) => panic ! ("network already finalized") , } ; * instantiate_fn = DebugInstantiate :: Finalized (sink_expr , source_expr , connect_fn) ; } } pub fn connect_network (& mut self , seen_tees : & mut SeenTees < 'a >) { self . transform_children (| n , s | n . connect_network (s) , seen_tees) ; if let HfPlusNode :: Network { instantiate_fn , .. } = self { match instantiate_fn { DebugInstantiate :: Building () => panic ! ("network not built") , DebugInstantiate :: Finalized (_ , _ , ref connect_fn) => { connect_fn () ; } } } } pub fn transform_children (& mut self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) { match self { HfPlusNode :: Placeholder => { panic ! () ; } HfPlusNode :: Source { .. } => { } HfPlusNode :: CycleSource { .. } => { } HfPlusNode :: Tee { inner } => { if let Some (transformed) = seen_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { * inner = transformed . clone () ; } else { let transformed_cell = Rc :: new (RefCell :: new (HfPlusNode :: Placeholder)) ; seen_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , transformed_cell . clone () ,) ; let mut orig = inner . replace (HfPlusNode :: Placeholder) ; transform (& mut orig , seen_tees) ; * transformed_cell . borrow_mut () = orig ; * inner = transformed_cell ; } } HfPlusNode :: Persist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Unpersist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Delta (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Union (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossProduct (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossSingleton (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Join (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Difference (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: AntiJoin (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Map { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FlatMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Filter { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FilterMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Sort (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: DeferTick (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Enumerate (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Inspect { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Unique (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Fold { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FoldKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Reduce { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: ReduceKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Network { input , .. } => { transform (input . as_mut () , seen_tees) ; } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) -> (syn :: Ident , usize) { match self { HfPlusNode :: Placeholder => { panic ! () } HfPlusNode :: Persist (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let persist_id = * next_stmt_id ; * next_stmt_id += 1 ; let persist_ident = syn :: Ident :: new (& format ! ("stream_{}" , persist_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # persist_ident = # inner_ident -> persist ::<'static > () ; }) ; (persist_ident , location) } HfPlusNode :: Unpersist (_) => { panic ! ("Unpersist is a marker node and should have been optimized away. This is likely a compiler bug.") } HfPlusNode :: Delta (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let delta_id = * next_stmt_id ; * next_stmt_id += 1 ; let delta_ident = syn :: Ident :: new (& format ! ("stream_{}" , delta_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # delta_ident = # inner_ident -> multiset_delta () ; }) ; (delta_ident , location) } HfPlusNode :: Source { source , location_kind , } => { let source_id = * next_stmt_id ; * next_stmt_id += 1 ; let source_ident = syn :: Ident :: new (& format ! ("stream_{}" , source_id) , Span :: call_site ()) ; let source_stmt = match source { HfPlusSource :: Stream (expr) => { parse_quote ! { # source_ident = source_stream (# expr) ; } } HfPlusSource :: Iter (expr) => { parse_quote ! { # source_ident = source_iter (# expr) ; } } HfPlusSource :: Interval (expr) => { parse_quote ! { # source_ident = source_interval (# expr) ; } } HfPlusSource :: Spin () => { parse_quote ! { # source_ident = spin () ; } } } ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; graph_builders . entry (* location_id) . or_default () . add_statement (source_stmt) ; (source_ident , * location_id) } HfPlusNode :: CycleSource { ident , location_kind , } => { let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; (ident . clone () , * location_id) } HfPlusNode :: Tee { inner } => { if let Some (ret) = built_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { ret . clone () } else { let (inner_ident , inner_location_id) = inner . borrow () . emit (graph_builders , built_tees , next_stmt_id) ; let tee_id = * next_stmt_id ; * next_stmt_id += 1 ; let tee_ident = syn :: Ident :: new (& format ! ("stream_{}" , tee_id) , Span :: call_site ()) ; let builder = graph_builders . entry (inner_location_id) . or_default () ; builder . add_statement (parse_quote ! { # tee_ident = # inner_ident -> tee () ; }) ; built_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , (tee_ident . clone () , inner_location_id) ,) ; (tee_ident , inner_location_id) } } HfPlusNode :: Union (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "union inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let union_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # union_ident = union () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [0] # union_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # union_ident ; }) ; (union_ident , left_location_id) } HfPlusNode :: CrossSingleton (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "cross_singleton inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let cross_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # cross_ident = cross_singleton () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [input] # cross_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [single] # cross_ident ; }) ; (cross_ident , left_location_id) } HfPlusNode :: CrossProduct (..) | HfPlusNode :: Join (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: CrossProduct (..)) { parse_quote ! (cross_join_multiset) } else { parse_quote ! (join_multiset) } ; let (HfPlusNode :: CrossProduct (left , right) | HfPlusNode :: Join (left , right)) = self else { unreachable ! () } ; let (left_inner , left_was_persist) = if let HfPlusNode :: Persist (left) = left . as_ref () { (left , true) } else { (left , false) } ; let (right_inner , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left_inner . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right_inner . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "join / cross product inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; match (left_was_persist , right_was_persist) { (true , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'static > () ; }) ; } (true , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'tick > () ; }) ; } (false , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } (false , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } } ; builder . add_statement (parse_quote ! { # left_ident -> [0] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Difference (..) | HfPlusNode :: AntiJoin (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Difference (..)) { parse_quote ! (difference_multiset) } else { parse_quote ! (anti_join_multiset) } ; let (HfPlusNode :: Difference (left , right) | HfPlusNode :: AntiJoin (left , right)) = self else { unreachable ! () } ; let (right , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "difference / anti join inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; if right_was_persist { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } else { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } builder . add_statement (parse_quote ! { # left_ident -> [pos] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [neg] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Map { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let map_id = * next_stmt_id ; * next_stmt_id += 1 ; let map_ident = syn :: Ident :: new (& format ! ("stream_{}" , map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # map_ident = # input_ident -> map (# f) ; }) ; (map_ident , input_location_id) } HfPlusNode :: FlatMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let flat_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let flat_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , flat_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # flat_map_ident = # input_ident -> flat_map (# f) ; }) ; (flat_map_ident , input_location_id) } HfPlusNode :: Filter { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_ident = # input_ident -> filter (# f) ; }) ; (filter_ident , input_location_id) } HfPlusNode :: FilterMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_map_ident = # input_ident -> filter_map (# f) ; }) ; (filter_map_ident , input_location_id) } HfPlusNode :: Sort (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sort_id = * next_stmt_id ; * next_stmt_id += 1 ; let sort_ident = syn :: Ident :: new (& format ! ("stream_{}" , sort_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # sort_ident = # input_ident -> sort () ; }) ; (sort_ident , input_location_id) } HfPlusNode :: DeferTick (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let defer_tick_id = * next_stmt_id ; * next_stmt_id += 1 ; let defer_tick_ident = syn :: Ident :: new (& format ! ("stream_{}" , defer_tick_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # defer_tick_ident = # input_ident -> defer_tick_lazy () ; }) ; (defer_tick_ident , input_location_id) } HfPlusNode :: Enumerate (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let enumerate_id = * next_stmt_id ; * next_stmt_id += 1 ; let enumerate_ident = syn :: Ident :: new (& format ! ("stream_{}" , enumerate_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # enumerate_ident = # input_ident -> enumerate () ; }) ; (enumerate_ident , input_location_id) } HfPlusNode :: Inspect { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let inspect_id = * next_stmt_id ; * next_stmt_id += 1 ; let inspect_ident = syn :: Ident :: new (& format ! ("stream_{}" , inspect_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # inspect_ident = # input_ident -> inspect (# f) ; }) ; (inspect_ident , input_location_id) } HfPlusNode :: Unique (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let unique_id = * next_stmt_id ; * next_stmt_id += 1 ; let unique_ident = syn :: Ident :: new (& format ! ("stream_{}" , unique_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # unique_ident = # input_ident -> unique ::<'tick > () ; }) ; (unique_ident , input_location_id) } HfPlusNode :: Fold { .. } | HfPlusNode :: FoldKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Fold { .. }) { parse_quote ! (fold) } else { parse_quote ! (fold_keyed) } ; let (HfPlusNode :: Fold { init , acc , input } | HfPlusNode :: FoldKeyed { init , acc , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let fold_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'static > (# init , # acc) ; }) ; } else { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'tick > (# init , # acc) ; }) ; } (fold_ident , input_location_id) } HfPlusNode :: Reduce { .. } | HfPlusNode :: ReduceKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Reduce { .. }) { parse_quote ! (reduce) } else { parse_quote ! (reduce_keyed) } ; let (HfPlusNode :: Reduce { f , input } | HfPlusNode :: ReduceKeyed { f , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let reduce_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'static > (# f) ; }) ; } else { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'tick > (# f) ; }) ; } (reduce_ident , input_location_id) } HfPlusNode :: Network { from_location : _ , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input , } => { let (sink_expr , source_expr , _connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { panic ! ("Expected the network to be finalized") } DebugInstantiate :: Finalized (sink , source , connect_fn) => { (sink , source , connect_fn) } } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sender_builder = graph_builders . entry (input_location_id) . or_default () ; if let Some (serialize_pipeline) = serialize_pipeline { sender_builder . add_statement (parse_quote ! { # input_ident -> # serialize_pipeline -> dest_sink (# sink_expr) ; }) ; } else { sender_builder . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink_expr) ; }) ; } let to_id = match to_location { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let receiver_builder = graph_builders . entry (* to_id) . or_default () ; let receiver_stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let receiver_stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , receiver_stream_id) , Span :: call_site ()) ; if let Some (deserialize_pipeline) = deserialize_pipeline { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) -> # deserialize_pipeline ; }) ; } else { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) ; }) ; } (receiver_stream_ident , * to_id) } } } } } pub mod persist_pullup { pub use std :: cell :: RefCell ; pub use std :: collections :: HashSet ; pub use std :: ops :: Deref ; pub use crate :: ir :: * ; pub fn persist_pullup_node < 'a > (node : & mut HfPlusNode < 'a > , seen_tees : & mut SeenTees < 'a > , persist_pulled_tees : & mut HashSet < * const RefCell < HfPlusNode < 'a > > > ,) { node . transform_children (| n , s | persist_pullup_node (n , s , persist_pulled_tees) , seen_tees ,) ; match node { HfPlusNode :: Unpersist (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Unpersist (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Delta (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Delta (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Tee { inner } => { if persist_pulled_tees . contains (& (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >)) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } else { let inner_borrow = inner . borrow () ; if let HfPlusNode :: Persist (_) = inner_borrow . deref () { drop (inner_borrow) ; persist_pulled_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >) ; if let HfPlusNode :: Persist (box behind_persist) = inner . replace (HfPlusNode :: Placeholder) { * inner . borrow_mut () = behind_persist ; } else { unreachable ! () } * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } } } HfPlusNode :: Map { f : _ , input : HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Map { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Map { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: FlatMap { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: FlatMap { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: FlatMap { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Filter { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Filter { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Filter { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Network { input : box HfPlusNode :: Persist (_) , .. } => { if let HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Union (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Union (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Union (left , right))) ; } else { unreachable ! () } } HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: CrossProduct (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,) ,)))) ; } else { unreachable ! () } } HfPlusNode :: Join (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Join (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: Join (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,))))) ; } else { unreachable ! () } } _ => { } } } pub fn persist_pullup (ir : Vec < HfPlusLeaf >) -> Vec < HfPlusLeaf > { let mut seen_tees = Default :: default () ; let mut persist_pulled_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| n , s | persist_pullup_node (n , s , & mut persist_pulled_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn persist_pullup_through_map () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } # [test] fn persist_pullup_behind_tee () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; let before_tee = flow . source_iter (& process , q ! (0 .. 10)) . tick_batch () . persist () ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } } } pub mod profiler { pub use std :: cell :: RefCell ; pub use hydroflow :: futures :: channel :: mpsc :: UnboundedSender ; pub use stageleft :: * ; pub use crate as hydroflow_plus ; pub use crate :: ir :: * ; pub use crate :: RuntimeContext ; pub fn increment_counter (count : & mut u64) { * count += 1 ; } pub fn quoted_any_fn < 'a , F : Fn (& usize) + 'a , Q : IntoQuotedMut < 'a , F > > (q : Q) -> Q { q } # [doc = " Add a profiling node before each node to count the cardinality of its input"] pub fn add_profiling_node < 'a > (node : & mut HfPlusNode < 'a > , _context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > , id : & mut u32 , seen_tees : & mut SeenTees < 'a > ,) { let my_id = * id ; * id += 1 ; node . transform_children (| node , seen_tees | { add_profiling_node (node , _context , counters , counter_queue , id , seen_tees) } , seen_tees ,) ; let orig_node = std :: mem :: replace (node , HfPlusNode :: Placeholder) ; * node = HfPlusNode :: Inspect { f : quoted_any_fn (q ! ({ counter_queue . borrow () . unbounded_send ((my_id as usize , counters . borrow () [my_id as usize])) . unwrap () ; counters . borrow_mut () [my_id as usize] = 0 ; move | _ | { hydroflow_plus :: profiler :: increment_counter (& mut counters . borrow_mut () [my_id as usize] ,) ; } })) . splice () . into () , input : Box :: new (orig_node) , } } # [doc = " Count the cardinality of each input and periodically output to a file"] pub fn profiling < 'a > (ir : Vec < HfPlusLeaf < 'a > > , context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > ,) -> Vec < HfPlusLeaf < 'a > > { let mut id = 0 ; let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | { add_profiling_node (node , context , counters , counter_queue , & mut id , seen_tees) } , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn profiler_wrapping_all_operators () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let runtime_context = flow . runtime_context () ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (& built . ir ()) ; let counters = RuntimeData :: new ("Fake") ; let counter_queue = RuntimeData :: new ("Fake") ; let pushed_down = built . with_default_optimize () . optimize_with (| ir | super :: profiling (ir , runtime_context , counters , counter_queue)) ; insta :: assert_debug_snapshot ! (& pushed_down . ir ()) ; let _ = pushed_down . compile_no_network :: < MultiGraph > () ; } } } pub mod properties { pub use std :: collections :: HashSet ; pub use stageleft :: * ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , SeenTees } ; pub use crate :: properties :: PropertyDatabase ; # [doc = " Allows us to convert the hydroflow datatype for folds to a binary operation for the algebra"] # [doc = " property tests."] # [allow (dead_code)] pub fn convert_hf_to_binary < I , A : Default , F : Fn (& mut A , I) > (f : F) -> impl Fn (I , I) -> A { move | a , b | { let mut acc = Default :: default () ; f (& mut acc , a) ; f (& mut acc , b) ; acc } } # [cfg (stageleft_macro)] impl PropertyDatabase { # [doc = " Tags the expression as commutative."] pub fn add_commutative_tag < 'a , I , A , F : Fn (& mut A , I) , Q : Quoted < 'a , F > + Clone > (& mut self , expr : Q ,) -> Q { let expr_clone = expr . clone () ; self . commutative . insert (expr_clone . splice ()) ; expr } pub fn is_tagged_commutative (& self , expr : & syn :: Expr) -> bool { self . commutative . contains (expr) } } pub fn properties_optimize_node < 'a > (node : & mut HfPlusNode < 'a > , db : & PropertyDatabase , seen_tees : & mut SeenTees < 'a > ,) { node . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , seen_tees ,) ; match node { HfPlusNode :: ReduceKeyed { f , .. } if db . is_tagged_commutative (& f . 0) => { dbg ! ("IDENTIFIED COMMUTATIVE OPTIMIZATION for {:?}" , & f) ; } _ => { } } } pub fn properties_optimize < 'a > (ir : Vec < HfPlusLeaf < 'a > > , db : & PropertyDatabase ,) -> Vec < HfPlusLeaf < 'a > > { let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use super :: * ; use crate :: deploy :: SingleProcessGraph ; use crate :: FlowBuilder ; # [test] fn test_property_database () { let mut db = PropertyDatabase :: default () ; assert ! (! db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; let _ = db . add_commutative_tag (q ! (| a : & mut i32 , b : i32 | * a += b)) ; assert ! (db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; } # [test] fn test_property_optimized () { let flow = FlowBuilder :: new () ; let mut database = PropertyDatabase :: default () ; let process = flow . process :: < () > () ; let counter_func = q ! (| count : & mut i32 , _ | * count += 1) ; let _ = database . add_commutative_tag (counter_func) ; flow . source_iter (& process , q ! (vec ! [])) . map (q ! (| string : String | (string , ()))) . tick_batch () . fold_keyed (q ! (|| 0) , counter_func) . all_ticks () . for_each (q ! (| (string , count) | println ! ("{}: {}" , string , count))) ; let built = flow . finalize () . optimize_with (| ir | properties_optimize (ir , & database)) . with_default_optimize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let _ = built . compile_no_network :: < SingleProcessGraph > () ; } } } pub use crate :: RuntimeContext ; # [cfg (stageleft_macro)] impl Copy for RuntimeContext < '_ > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Context > for RuntimeContext < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (quote ! (& context))) } } pub use crate :: HfCompiled ; # [cfg (stageleft_macro)] impl < 'a , ID > HfCompiled < 'a , ID > { pub fn hydroflow_ir (& self) -> & BTreeMap < usize , HydroflowGraph > { & self . hydroflow_ir } } # [cfg (stageleft_macro)] impl < 'a > HfCompiled < 'a , usize > { pub fn with_dynamic_id (self , id : impl Quoted < 'a , usize >) -> HfBuiltWithId < 'a > { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; let mut conditioned_tokens = None ; for (subgraph_id , flat_graph) in self . hydroflow_ir { let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; let my_extra_stmts = self . extra_stmts . get (& subgraph_id) . cloned () . unwrap_or_default () ; if let Some (conditioned_tokens) = conditioned_tokens . as_mut () { * conditioned_tokens = syn :: parse_quote ! { # conditioned_tokens else if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } } ; } else { conditioned_tokens = Some (syn :: parse_quote ! { if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } }) ; } } let conditioned_tokens : TokenStream = conditioned_tokens . unwrap () ; let id = id . splice () ; HfBuiltWithId { tokens : syn :: parse_quote ! ({ let __given_id = # id ; # conditioned_tokens else { panic ! ("Invalid node id: {}" , __given_id) ; } }) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfCompiled < 'a , () > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfCompiled < 'a , () > { fn to_tokens (mut self) -> (Option < TokenStream > , Option < TokenStream >) { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; if self . hydroflow_ir . len () != 1 { panic ! ("Expected exactly one subgraph in the Hydroflow IR") ; } let flat_graph = self . hydroflow_ir . remove (& 0) . unwrap () ; let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; (None , Some (tokens)) } } pub use crate :: HfBuiltWithId ; # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfBuiltWithId < 'a > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfBuiltWithId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (self . tokens)) } }
[INFO] [stdout]   |
[INFO] [stdout] help: ...otherwise replace it with an invocation of macro `deref`
[INFO] [stdout]   |
[INFO] [stdout] 1 - pub use std :: collections :: BTreeMap ; pub use std :: marker :: PhantomData ; pub use hydroflow :: scheduled :: context :: Context ; pub use hydroflow :: scheduled :: graph :: Hydroflow ; pub use hydroflow :: * ; pub use lang :: graph :: { partition_graph , HydroflowGraph } ; pub use proc_macro2 :: TokenStream ; pub use quote :: quote ; pub use stageleft :: runtime_support :: FreeVariable ; pub use stageleft :: Quoted ; pub mod runtime_support { pub use bincode ; } pub mod stream { pub use std :: cell :: RefCell ; pub use std :: hash :: Hash ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow :: bytes :: Bytes ; pub use hydroflow :: futures :: Sink ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: quote ; pub use serde :: de :: DeserializeOwned ; pub use serde :: Serialize ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use syn :: parse_quote ; pub use crate :: builder :: { ClusterIds , FlowLeaves } ; pub use crate :: cycle :: { CycleCollection , CycleComplete } ; pub use crate :: ir :: { DebugInstantiate , HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { CanSend , Location , LocationId } ; pub use crate :: { Cluster , Optional , Singleton } ; pub use crate :: stream :: Unbounded ; pub use crate :: stream :: Bounded ; pub use crate :: stream :: NoTick ; pub use crate :: stream :: Tick ; pub use crate :: stream :: Stream ; # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Stream { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Stream < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Stream { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , C , N > > ,) -> Stream < 'a , (T , O) , W , C , N > where O : Clone , { let other : Optional < 'a , O , Bounded , C , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn cross_product < O > (self , other : Stream < 'a , O , W , C , N >) -> Stream < 'a , (T , O) , W , C , N > where T : Clone , O : Clone , { if self . location_kind != other . location_kind { panic ! ("cross_product must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossProduct (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn union (self , other : Stream < 'a , T , W , C , N >) -> Stream < 'a , T , W , C , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn dest_sink < S : Unpin + Sink < T > + 'a > (self , sink : impl Quoted < 'a , S >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: DestSink { sink : sink . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn first (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } # [doc = " Allow this stream through if the other stream has elements, otherwise the output is empty."] pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } # [doc = " Allow this stream through if the other stream is empty, otherwise the output is empty."] pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn enumerate (self) -> Stream < 'a , (usize , T) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Enumerate (Box :: new (self . ir_node . into_inner ())) ,) } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn sort (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Ord , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Sort (Box :: new (self . ir_node . into_inner ())) ,) } pub fn count (self) -> Singleton < 'a , usize , Bounded , Tick , N > { self . fold (q ! (|| 0usize) , q ! (| count , _ | * count += 1)) } pub fn delta (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } pub fn unique (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Eq + Hash , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unique (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn tick_batch (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_prefix (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { self . tick_batch () . persist () } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn for_each < F : Fn (T) + 'a > (self , f : impl IntoQuotedMut < 'a , F >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: ForEach { input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , f : f . splice () . into () , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Unbounded , NoTick , N > { pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . tick_batch () . continue_if (samples . first ()) . all_ticks () } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Unbounded , NoTick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , C , N : Location > Stream < 'a , T , Bounded , C , N > { pub fn filter_not_in (self , other : Stream < 'a , T , Bounded , C , N >) -> Stream < 'a , T , Bounded , C , N > where T : Eq + Hash , { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Difference (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Stream < 'a , & T , W , C , N > { pub fn cloned (self) -> Stream < 'a , T , W , C , N > { self . map (q ! (| d | d . clone ())) } } # [cfg (stageleft_macro)] impl < 'a , K , V1 , W , C , N : Location > Stream < 'a , (K , V1) , W , C , N > { pub fn join < W2 , V2 > (self , n : Stream < 'a , (K , V2) , W2 , C , N > ,) -> Stream < 'a , (K , (V1 , V2)) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Join (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } pub fn anti_join < W2 > (self , n : Stream < 'a , K , W2 , C , N >) -> Stream < 'a , (K , V1) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("anti_join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: AntiJoin (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , K : Eq + Hash , V , N : Location > Stream < 'a , (K , V) , Bounded , Tick , N > { pub fn fold_keyed < A , I : Fn () -> A + 'a , F : Fn (& mut A , V) + 'a > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , A) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FoldKeyed { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce_keyed < F : Fn (& mut V , V) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , V) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: ReduceKeyed { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } pub fn get_this_crate () -> TokenStream { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , Span :: call_site ()) ; quote ! { # ident } } } } pub fn serialize_bincode < T : Serialize > (is_demux : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if is_demux { parse_quote ! { map (| (id , data) | { (id , # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into ()) }) } } else { parse_quote ! { map (| data | { # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into () }) } } } pub fn deserialize_bincode < T : DeserializeOwned > (tagged : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if tagged { parse_quote ! { map (| res | { let (id , b) = res . unwrap () ; (id , # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& b) . unwrap ()) }) } } else { parse_quote ! { map (| res | { # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& res . unwrap ()) . unwrap () }) } } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn send_bincode < N2 : Location , CoreType > (self , other : & N2 ,) -> Stream < 'a , N :: Out < CoreType > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T > , CoreType : Serialize + DeserializeOwned , { let serialize_pipeline = Some (serialize_bincode :: < CoreType > (N :: is_demux ())) ; let deserialize_pipeline = Some (deserialize_bincode :: < CoreType > (N :: is_tagged ())) ; Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bytes < N2 : Location > (self , other : & N2 ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T > , { Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline : None , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline : if N :: is_tagged () { Some (parse_quote ! (map (| (id , b) | (id , b . unwrap () . freeze ())))) } else { Some (parse_quote ! (map (| b | b . unwrap () . freeze ()))) } , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bincode_interleaved < N2 : Location , Tag , CoreType > (self , other : & N2 ,) -> Stream < 'a , CoreType , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T , Out < CoreType > = (Tag , CoreType) > , CoreType : Serialize + DeserializeOwned , { self . send_bincode :: < N2 , CoreType > (other) . map (q ! (| (_ , b) | b)) } pub fn send_bytes_interleaved < N2 : Location , Tag > (self , other : & N2 ,) -> Stream < 'a , Bytes , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T , Out < Bytes > = (Tag , Bytes) > , { self . send_bytes :: < N2 > (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bincode < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < T > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) > , T : Clone + Serialize + DeserializeOwned , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bincode (other) } pub fn broadcast_bincode_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , T , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) , Out < T > = (Tag , T) > + 'a , T : Clone + Serialize + DeserializeOwned , { self . broadcast_bincode (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bytes < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) > + 'a , T : Clone , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bytes (other) } pub fn broadcast_bytes_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , Bytes , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) , Out < Bytes > = (Tag , Bytes) > + 'a , T : Clone , { self . broadcast_bytes (other) . map (q ! (| (_ , b) | b)) } } } pub use stream :: { Bounded , NoTick , Stream , Tick , Unbounded } ; pub mod singleton { pub use std :: cell :: RefCell ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use crate :: builder :: FlowLeaves ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial , CycleComplete } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: Stream ; pub use crate :: singleton :: CrossResult ; # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Singleton < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Singleton :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } pub use crate :: singleton :: Singleton ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Singleton { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleComplete < 'a > for Singleton < 'a , T , Bounded , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleCollectionWithInitial < 'a > for Singleton < 'a , T , Bounded , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , initial : Self , l : LocationId ,) -> Self { Singleton :: new (l , ir_leaves , HfPlusNode :: Union (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , }) , initial . ir_node . into_inner () . into () ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Singleton < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Singleton { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , U , W , C , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (Self :: other_ir_node (other)) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Singleton < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CrossSingleton (Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , Box :: new (HfPlusNode :: Unpersist (Box :: new (Self :: other_ir_node (other)))) ,))) ,) } } pub use crate :: singleton :: Optional ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Optional { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } pub fn some (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: new (singleton . location_kind , singleton . ir_leaves , singleton . ir_node . into_inner () ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > From < Singleton < 'a , T , W , C , N > > for Optional < 'a , T , W , C , N > { fn from (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: some (singleton) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Optional < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Optional { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn into_stream (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , Tick , N > > ,) -> Optional < 'a , (T , O) , Bounded , Tick , N > where O : Clone , { let other : Optional < 'a , O , Bounded , Tick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn union (self , other : Optional < 'a , T , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Optional < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_samples (self) -> Stream < 'a , T , Unbounded , NoTick , N > { self . latest_tick () . all_ticks () } pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . latest_tick () . continue_if (samples . first ()) . latest () . tick_samples () } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Unbounded , NoTick , N > > ,) -> Optional < 'a , (T , O) , Unbounded , NoTick , N > where O : Clone , { let other : Optional < 'a , O , Unbounded , NoTick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } self . latest_tick () . cross_singleton (other . latest_tick ()) . latest () } } } pub use singleton :: { Optional , Singleton } ; pub mod location { pub use std :: marker :: PhantomData ; pub use crate :: location :: LocationId ; pub use crate :: location :: Location ; pub use crate :: location :: Process ; # [cfg (stageleft_macro)] impl < P > Clone for Process < P > { fn clone (& self) -> Self { Process { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < P > Location for Process < P > { fn id (& self) -> LocationId { LocationId :: Process (self . id) } } pub use crate :: location :: Cluster ; # [cfg (stageleft_macro)] impl < C > Clone for Cluster < C > { fn clone (& self) -> Self { Cluster { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < C > Location for Cluster < C > { fn id (& self) -> LocationId { LocationId :: Cluster (self . id) } } pub use crate :: location :: CanSend ; # [cfg (stageleft_macro)] impl < P1 , P2 > CanSend < Process < P2 > > for Process < P1 > { type In < T > = T ; type Out < T > = T ; fn is_demux () -> bool { false } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < P1 , C2 > CanSend < Cluster < C2 > > for Process < P1 > { type In < T > = (u32 , T) ; type Out < T > = T ; fn is_demux () -> bool { true } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < C1 , P2 > CanSend < Process < P2 > > for Cluster < C1 > { type In < T > = T ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { false } fn is_tagged () -> bool { true } } # [cfg (stageleft_macro)] impl < C1 , C2 > CanSend < Cluster < C2 > > for Cluster < C1 > { type In < T > = (u32 , T) ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { true } fn is_tagged () -> bool { true } } } pub use location :: { Cluster , Process } ; pub mod deploy { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use stageleft :: Quoted ; pub mod graphs { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use super :: { LocalDeploy , Node , ProcessSpec } ; pub use crate :: deploy :: graphs :: SingleProcessGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for SingleProcessGraph { type Process = SingleNode ; type Cluster = SingleNode ; type Meta = () ; type GraphId = () ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { SingleNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { SingleNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , SingleProcessGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> SingleNode { SingleNode { } } } pub use crate :: deploy :: graphs :: SingleNode ; # [cfg (stageleft_macro)] impl Node for SingleNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } pub use crate :: deploy :: graphs :: MultiGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for MultiGraph { type Process = MultiNode ; type Cluster = MultiNode ; type Meta = () ; type GraphId = usize ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { MultiNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { MultiNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , MultiGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> MultiNode { MultiNode { } } } pub use crate :: deploy :: graphs :: MultiNode ; # [cfg (stageleft_macro)] impl Node for MultiNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } } pub use graphs :: * ; pub use crate :: deploy :: LocalDeploy ; pub use crate :: deploy :: Deploy ; # [cfg (stageleft_macro)] impl < 'a , T : Deploy < 'a , Process = N , Cluster = C , Meta = M , GraphId = R > , N : Node < Meta = M > , C : Node < Meta = M > , M : Default , R , > LocalDeploy < 'a > for T { type Process = N ; type Cluster = C ; type Meta = M ; type GraphId = R ; fn has_trivial_node () -> bool { < T as Deploy < 'a > > :: has_trivial_node () } fn trivial_process (id : usize) -> Self :: Process { < T as Deploy < 'a > > :: trivial_process (id) } fn trivial_cluster (id : usize) -> Self :: Cluster { < T as Deploy < 'a > > :: trivail_cluster (id) } } pub use crate :: deploy :: ProcessSpec ; pub use crate :: deploy :: ClusterSpec ; pub use crate :: deploy :: Node ; } pub use deploy :: { ClusterSpec , Deploy , ProcessSpec } ; pub mod cycle { pub use std :: marker :: PhantomData ; pub use crate :: builder :: FlowLeaves ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: cycle :: CycleComplete ; pub use crate :: cycle :: CycleCollection ; pub use crate :: cycle :: CycleCollectionWithInitial ; pub use crate :: cycle :: HfCycle ; # [cfg (stageleft_macro)] impl < 'a , S : CycleComplete < 'a > > HfCycle < 'a , S > { pub fn complete (self , stream : S) { let ident = self . ident ; S :: complete (stream , ident) } } } pub use cycle :: HfCycle ; pub mod builder { pub use std :: cell :: RefCell ; pub use std :: collections :: HashMap ; pub use std :: marker :: PhantomData ; pub use std :: rc :: Rc ; pub use std :: time :: Duration ; pub use hydroflow :: futures :: stream :: Stream as FuturesStream ; pub use hydroflow :: { tokio , tokio_stream } ; pub use internal :: TokenStream ; pub use proc_macro2 :: Span ; pub use quote :: quote ; pub use runtime_support :: FreeVariable ; pub use stageleft :: * ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Cluster , Location , LocationId , Process } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: { HfCycle , Optional , RuntimeContext , Singleton , Stream } ; pub mod built { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use hydroflow_lang :: graph :: { eliminate_extra_unions_tees , HydroflowGraph } ; pub use super :: deploy :: { DeployFlow , DeployResult } ; pub use crate :: deploy :: { ClusterSpec , Deploy , LocalDeploy , ProcessSpec } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Cluster , Process } ; pub use crate :: HfCompiled ; pub use crate :: builder :: built :: BuiltFlow ; # [cfg (stageleft_macro)] impl < 'a > Drop for BuiltFlow < 'a > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped BuiltFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn ir (& self) -> & Vec < HfPlusLeaf < 'a > > { & self . ir } pub fn optimize_with (mut self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> BuiltFlow < 'a > { self . used = true ; BuiltFlow { ir : f (std :: mem :: take (& mut self . ir)) , processes : std :: mem :: take (& mut self . processes) , clusters : std :: mem :: take (& mut self . clusters) , used : false , _phantom : PhantomData , } } } pub fn build_inner (ir : & mut Vec < HfPlusLeaf >) -> BTreeMap < usize , HydroflowGraph > { let mut builders = BTreeMap :: new () ; let mut built_tees = HashMap :: new () ; let mut next_stmt_id = 0 ; for leaf in ir { leaf . emit (& mut builders , & mut built_tees , & mut next_stmt_id) ; } builders . into_iter () . map (| (k , v) | { let (mut flat_graph , _ , _) = v . build () ; eliminate_extra_unions_tees (& mut flat_graph) ; (k , flat_graph) }) . collect () } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn compile_no_network < D : LocalDeploy < 'a > > (mut self) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; HfCompiled { hydroflow_ir : build_inner (& mut self . ir) , extra_stmts : BTreeMap :: new () , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> BuiltFlow < 'a > { self . optimize_with (crate :: persist_pullup :: persist_pullup) } fn into_deploy < D : LocalDeploy < 'a > > (mut self) -> DeployFlow < 'a , D > { self . used = true ; let processes = if D :: has_trivial_node () { self . processes . iter () . map (| id | (* id , D :: trivial_process (* id))) . collect () } else { HashMap :: new () } ; let clusters = if D :: has_trivial_node () { self . clusters . iter () . map (| id | (* id , D :: trivial_cluster (* id))) . collect () } else { HashMap :: new () } ; DeployFlow { ir : std :: mem :: take (& mut self . ir) , nodes : processes , clusters , used : false , _phantom : PhantomData , } } pub fn with_process < P , D : LocalDeploy < 'a > > (self , process : & Process < P > , spec : impl ProcessSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_process (process , spec) } pub fn with_cluster < C , D : LocalDeploy < 'a > > (self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_cluster (cluster , spec) } pub fn compile < D : Deploy < 'a > + 'a > (self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . into_deploy :: < D > () . compile (env) } pub fn deploy < D : Deploy < 'a , CompileEnv = () > + 'a > (self , env : & mut D :: InstantiateEnv ,) -> DeployResult < 'a , D > { self . into_deploy :: < D > () . deploy (env) } } } pub mod deploy { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use proc_macro2 :: Span ; pub use stageleft :: Quoted ; pub use super :: built :: build_inner ; pub use crate :: deploy :: { LocalDeploy , Node } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: { Cluster , ClusterSpec , Deploy , HfCompiled , Process , ProcessSpec } ; pub use crate :: builder :: deploy :: DeployFlow ; # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > Drop for DeployFlow < 'a , D > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped DeployFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > DeployFlow < 'a , D > { pub fn with_process < P > (mut self , process : & Process < P > , spec : impl ProcessSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < P > () . to_string () ; self . nodes . insert (process . id , spec . build (process . id , & tag_name)) ; self } pub fn with_cluster < C > (mut self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < C > () . to_string () ; self . clusters . insert (cluster . id , spec . build (cluster . id , & tag_name)) ; self } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployFlow < 'a , D > { pub fn compile (mut self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; let mut seen_tees : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | leaf . compile_network :: < D > (env , & mut seen_tees , & self . nodes , & self . clusters)) . collect () ; let extra_stmts = self . extra_stmts (env) ; HfCompiled { hydroflow_ir : build_inner (& mut ir_leaves_networked) , extra_stmts , _phantom : PhantomData , } } fn extra_stmts (& self , env : & < D as Deploy < 'a > > :: CompileEnv) -> BTreeMap < usize , Vec < syn :: Stmt > > { let all_locations_count = self . nodes . len () + self . clusters . len () ; let mut extra_stmts : BTreeMap < usize , Vec < syn :: Stmt > > = BTreeMap :: new () ; for & c_id in self . clusters . keys () { let self_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , c_id) , Span :: call_site () ,) ; let self_id_expr = D :: cluster_self_id (env) . splice () ; extra_stmts . entry (c_id) . or_default () . push (syn :: parse_quote ! { let # self_id_ident = # self_id_expr ; }) ; for other_location in 0 .. all_locations_count { let other_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , c_id) , Span :: call_site () ,) ; let other_id_expr = D :: cluster_ids (env , c_id) . splice () ; extra_stmts . entry (other_location) . or_default () . push (syn :: parse_quote ! { let # other_id_ident = # other_id_expr ; }) ; } } extra_stmts } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a , CompileEnv = () > > DeployFlow < 'a , D > { # [must_use] pub fn deploy (mut self , env : & mut D :: InstantiateEnv) -> DeployResult < 'a , D > { self . used = true ; let mut seen_tees_instantiate : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | { leaf . compile_network :: < D > (& () , & mut seen_tees_instantiate , & self . nodes , & self . clusters ,) }) . collect () ; let mut compiled = build_inner (& mut ir_leaves_networked) ; let mut extra_stmts = self . extra_stmts (& ()) ; let mut meta = D :: Meta :: default () ; let (mut processes , mut clusters) = (std :: mem :: take (& mut self . nodes) . into_iter () . map (| (node_id , node) | { node . instantiate (env , & mut meta , compiled . remove (& node_id) . unwrap () , extra_stmts . remove (& node_id) . unwrap_or_default () ,) ; (node_id , node) }) . collect :: < HashMap < _ , _ > > () , std :: mem :: take (& mut self . clusters) . into_iter () . map (| (cluster_id , cluster) | { cluster . instantiate (env , & mut meta , compiled . remove (& cluster_id) . unwrap () , extra_stmts . remove (& cluster_id) . unwrap_or_default () ,) ; (cluster_id , cluster) }) . collect :: < HashMap < _ , _ > > () ,) ; for node in processes . values_mut () { node . update_meta (& meta) ; } for cluster in clusters . values_mut () { cluster . update_meta (& meta) ; } let mut seen_tees_connect = HashMap :: new () ; for leaf in ir_leaves_networked { leaf . connect_network (& mut seen_tees_connect) ; } DeployResult { processes , clusters , } } } pub use crate :: builder :: deploy :: DeployResult ; # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployResult < 'a , D > { pub fn get_process < P > (& self , p : & Process < P >) -> & D :: Process { let id = match p . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . processes . get (& id) . unwrap () } pub fn get_cluster < C > (& self , c : & Cluster < C >) -> & D :: Cluster { let id = match c . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . clusters . get (& id) . unwrap () } } } # [doc = " Tracks the leaves of the dataflow IR. This is referenced by"] # [doc = " `Stream` and `HfCycle` to build the IR. The inner option will"] # [doc = " be set to `None` when this builder is finalized."] pub type FlowLeaves < 'a > = Rc < RefCell < Option < Vec < HfPlusLeaf < 'a > > > > > ; pub use crate :: builder :: ClusterIds ; # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Vec < u32 > > for ClusterIds < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , & 'a Vec < u32 > > for ClusterIds < 'a > { } # [derive (Copy , Clone)] pub struct ClusterSelfId < 'a > { pub id : usize , pub _phantom : PhantomData < & 'a mut & 'a u32 > , } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < u32 > for ClusterSelfId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , u32 > for ClusterSelfId < 'a > { } pub use crate :: builder :: FlowBuilder ; # [cfg (stageleft_macro)] impl < 'a > Drop for FlowBuilder < 'a > { fn drop (& mut self) { if ! self . finalized { panic ! ("Dropped FlowBuilder without finalizing, you may have forgotten to call `with_default_optimize`, `optimize_with`, or `finalize`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > QuotedContext for FlowBuilder < 'a > { fn create () -> Self { FlowBuilder :: new () } } # [cfg (stageleft_macro)] impl < 'a > FlowBuilder < 'a > { # [allow (clippy :: new_without_default)] pub fn new () -> FlowBuilder < 'a > { FlowBuilder { ir_leaves : Rc :: new (RefCell :: new (Some (Vec :: new ()))) , nodes : RefCell :: new (vec ! []) , clusters : RefCell :: new (vec ! []) , cycle_ids : RefCell :: new (HashMap :: new ()) , next_node_id : RefCell :: new (0) , finalized : false , _phantom : PhantomData , } } pub fn finalize (mut self) -> built :: BuiltFlow < 'a > { self . finalized = true ; built :: BuiltFlow { ir : self . ir_leaves . borrow_mut () . take () . unwrap () , processes : self . nodes . replace (vec ! []) , clusters : self . clusters . replace (vec ! []) , used : false , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> built :: BuiltFlow < 'a > { self . finalize () . with_default_optimize () } pub fn optimize_with (self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> built :: BuiltFlow < 'a > { self . finalize () . optimize_with (f) } pub fn ir_leaves (& self) -> & FlowLeaves < 'a > { & self . ir_leaves } pub fn process < P > (& self) -> Process < P > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . nodes . borrow_mut () . push (id) ; Process { id , _phantom : PhantomData , } } pub fn cluster < C > (& self) -> Cluster < C > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . clusters . borrow_mut () . push (id) ; Cluster { id , _phantom : PhantomData , } } pub fn runtime_context (& self) -> RuntimeContext < 'a > { RuntimeContext { _phantom : PhantomData , } } pub fn cluster_members < C > (& self , cluster : & Cluster < C > ,) -> impl Quoted < 'a , & 'a Vec < u32 > > + Copy + 'a { ClusterIds { id : cluster . id , _phantom : PhantomData , } } pub fn cluster_self_id < C > (& self , cluster : & Cluster < C >) -> impl Quoted < 'a , u32 > + Copy + 'a { ClusterSelfId { id : cluster . id , _phantom : PhantomData , } } pub fn spin < L : Location > (& self , on : & L) -> Stream < 'a , () , Unbounded , NoTick , L > { Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Spin () , location_kind : on . id () , })) ,) } pub fn spin_batch < L : Location > (& self , on : & L , batch_size : impl Quoted < 'a , usize > + Copy + 'a ,) -> Stream < 'a , () , Bounded , Tick , L > { self . spin (on) . flat_map (q ! (move | _ | 0 .. batch_size)) . map (q ! (| _ | ())) . tick_batch () } pub fn source_stream < T , E : FuturesStream < Item = T > + Unpin , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Unbounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Stream (e . into ()) , location_kind : on . id () , })) ,) } pub fn source_iter < T , E : IntoIterator < Item = T > , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Bounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , })) ,) } pub fn singleton < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Singleton < 'a , T , Bounded , NoTick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Singleton :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,)))) ,) } pub fn singleton_first_tick < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Optional < 'a , T , Bounded , Tick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,) } pub fn source_interval < L : Location > (& self , on : & L , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , () , Unbounded , NoTick , L > { let interval = interval . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : on . id () , })) ,) } pub fn source_interval_delayed < L : Location > (& self , on : & L , delay : impl Quoted < 'a , Duration > + Copy + 'a , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , tokio :: time :: Instant , Unbounded , NoTick , L > { self . source_stream (on , q ! (tokio_stream :: wrappers :: IntervalStream :: new (tokio :: time :: interval_at (tokio :: time :: Instant :: now () + delay , interval))) ,) . tick_batch () . first () . latest () } pub fn cycle < S : CycleCollection < 'a > > (& self , on : & S :: Location) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , on . id ()) ,) } pub fn cycle_with_initial < S : CycleCollectionWithInitial < 'a > > (& self , on : & S :: Location , initial : S ,) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , initial , on . id ()) ,) } } } pub use builder :: FlowBuilder ; pub mod ir { pub use core :: panic ; pub use std :: cell :: RefCell ; pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow_lang :: graph :: FlatGraphBuilder ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: ToTokens ; pub use syn :: parse_quote ; pub use crate :: deploy :: Deploy ; pub use crate :: location :: LocationId ; pub use crate :: ir :: DebugExpr ; # [cfg (stageleft_macro)] impl From < syn :: Expr > for DebugExpr { fn from (expr : syn :: Expr) -> DebugExpr { DebugExpr (expr) } } # [cfg (stageleft_macro)] impl Deref for DebugExpr { type Target = syn :: Expr ; fn deref (& self) -> & Self :: Target { & self . 0 } } # [cfg (stageleft_macro)] impl ToTokens for DebugExpr { fn to_tokens (& self , tokens : & mut TokenStream) { self . 0 . to_tokens (tokens) ; } } # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugExpr { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "{}" , self . 0 . to_token_stream ()) } } pub use crate :: ir :: DebugInstantiate ; # [cfg (stageleft_macro)] impl < 'a > std :: fmt :: Debug for DebugInstantiate < 'a > { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<network instantiate>") } } pub use crate :: ir :: DebugPipelineFn ; # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugPipelineFn { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<function>") } } pub use crate :: ir :: HfPlusSource ; pub use crate :: ir :: HfPlusLeaf ; # [cfg (stageleft_macro)] impl < 'a > HfPlusLeaf < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . compile_network :: < D > (compile_env , s , nodes , clusters) ; } , seen_tees ,) } pub fn connect_network (self , seen_tees : & mut SeenTees < 'a >) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . connect_network (s) ; } , seen_tees ,) } pub fn transform_children (self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) -> HfPlusLeaf < 'a > { match self { HfPlusLeaf :: ForEach { f , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: ForEach { f , input } } HfPlusLeaf :: DestSink { sink , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: DestSink { sink , input } } HfPlusLeaf :: CycleSink { ident , location_kind , mut input , } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: CycleSink { ident , location_kind , input , } } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) { match self { HfPlusLeaf :: ForEach { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> for_each (# f) ; }) ; } HfPlusLeaf :: DestSink { sink , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink) ; }) ; } HfPlusLeaf :: CycleSink { ident , location_kind , input , } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; assert_eq ! (input_location_id , * location_id , "cycle_sink location mismatch") ; graph_builders . entry (* location_id) . or_default () . add_statement (parse_quote ! { # ident = # input_ident ; }) ; } } } } pub use crate :: ir :: HfPlusNode ; pub type SeenTees < 'a > = HashMap < * const RefCell < HfPlusNode < 'a > > , Rc < RefCell < HfPlusNode < 'a > > > > ; # [cfg (stageleft_macro)] impl < 'a > HfPlusNode < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (& mut self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) { self . transform_children (| n , s | n . compile_network :: < D > (compile_env , s , nodes , clusters) , seen_tees ,) ; if let HfPlusNode :: Network { from_location , to_location , instantiate_fn , .. } = self { let (sink_expr , source_expr , connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { let ((sink , source) , connect_fn) = match (from_location , to_location) { (LocationId :: Process (from) , LocationId :: Process (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: o2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Process (from) , LocationId :: Cluster (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: o2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Process (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: m2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Cluster (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: m2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } } ; (sink , source , connect_fn) } DebugInstantiate :: Finalized (_ , _ , _) => panic ! ("network already finalized") , } ; * instantiate_fn = DebugInstantiate :: Finalized (sink_expr , source_expr , connect_fn) ; } } pub fn connect_network (& mut self , seen_tees : & mut SeenTees < 'a >) { self . transform_children (| n , s | n . connect_network (s) , seen_tees) ; if let HfPlusNode :: Network { instantiate_fn , .. } = self { match instantiate_fn { DebugInstantiate :: Building () => panic ! ("network not built") , DebugInstantiate :: Finalized (_ , _ , ref connect_fn) => { connect_fn () ; } } } } pub fn transform_children (& mut self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) { match self { HfPlusNode :: Placeholder => { panic ! () ; } HfPlusNode :: Source { .. } => { } HfPlusNode :: CycleSource { .. } => { } HfPlusNode :: Tee { inner } => { if let Some (transformed) = seen_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { * inner = transformed . clone () ; } else { let transformed_cell = Rc :: new (RefCell :: new (HfPlusNode :: Placeholder)) ; seen_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , transformed_cell . clone () ,) ; let mut orig = inner . replace (HfPlusNode :: Placeholder) ; transform (& mut orig , seen_tees) ; * transformed_cell . borrow_mut () = orig ; * inner = transformed_cell ; } } HfPlusNode :: Persist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Unpersist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Delta (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Union (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossProduct (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossSingleton (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Join (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Difference (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: AntiJoin (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Map { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FlatMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Filter { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FilterMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Sort (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: DeferTick (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Enumerate (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Inspect { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Unique (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Fold { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FoldKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Reduce { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: ReduceKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Network { input , .. } => { transform (input . as_mut () , seen_tees) ; } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) -> (syn :: Ident , usize) { match self { HfPlusNode :: Placeholder => { panic ! () } HfPlusNode :: Persist (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let persist_id = * next_stmt_id ; * next_stmt_id += 1 ; let persist_ident = syn :: Ident :: new (& format ! ("stream_{}" , persist_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # persist_ident = # inner_ident -> persist ::<'static > () ; }) ; (persist_ident , location) } HfPlusNode :: Unpersist (_) => { panic ! ("Unpersist is a marker node and should have been optimized away. This is likely a compiler bug.") } HfPlusNode :: Delta (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let delta_id = * next_stmt_id ; * next_stmt_id += 1 ; let delta_ident = syn :: Ident :: new (& format ! ("stream_{}" , delta_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # delta_ident = # inner_ident -> multiset_delta () ; }) ; (delta_ident , location) } HfPlusNode :: Source { source , location_kind , } => { let source_id = * next_stmt_id ; * next_stmt_id += 1 ; let source_ident = syn :: Ident :: new (& format ! ("stream_{}" , source_id) , Span :: call_site ()) ; let source_stmt = match source { HfPlusSource :: Stream (expr) => { parse_quote ! { # source_ident = source_stream (# expr) ; } } HfPlusSource :: Iter (expr) => { parse_quote ! { # source_ident = source_iter (# expr) ; } } HfPlusSource :: Interval (expr) => { parse_quote ! { # source_ident = source_interval (# expr) ; } } HfPlusSource :: Spin () => { parse_quote ! { # source_ident = spin () ; } } } ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; graph_builders . entry (* location_id) . or_default () . add_statement (source_stmt) ; (source_ident , * location_id) } HfPlusNode :: CycleSource { ident , location_kind , } => { let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; (ident . clone () , * location_id) } HfPlusNode :: Tee { inner } => { if let Some (ret) = built_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { ret . clone () } else { let (inner_ident , inner_location_id) = inner . borrow () . emit (graph_builders , built_tees , next_stmt_id) ; let tee_id = * next_stmt_id ; * next_stmt_id += 1 ; let tee_ident = syn :: Ident :: new (& format ! ("stream_{}" , tee_id) , Span :: call_site ()) ; let builder = graph_builders . entry (inner_location_id) . or_default () ; builder . add_statement (parse_quote ! { # tee_ident = # inner_ident -> tee () ; }) ; built_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , (tee_ident . clone () , inner_location_id) ,) ; (tee_ident , inner_location_id) } } HfPlusNode :: Union (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "union inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let union_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # union_ident = union () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [0] # union_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # union_ident ; }) ; (union_ident , left_location_id) } HfPlusNode :: CrossSingleton (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "cross_singleton inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let cross_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # cross_ident = cross_singleton () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [input] # cross_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [single] # cross_ident ; }) ; (cross_ident , left_location_id) } HfPlusNode :: CrossProduct (..) | HfPlusNode :: Join (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: CrossProduct (..)) { parse_quote ! (cross_join_multiset) } else { parse_quote ! (join_multiset) } ; let (HfPlusNode :: CrossProduct (left , right) | HfPlusNode :: Join (left , right)) = self else { unreachable ! () } ; let (left_inner , left_was_persist) = if let HfPlusNode :: Persist (left) = left . as_ref () { (left , true) } else { (left , false) } ; let (right_inner , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left_inner . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right_inner . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "join / cross product inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; match (left_was_persist , right_was_persist) { (true , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'static > () ; }) ; } (true , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'tick > () ; }) ; } (false , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } (false , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } } ; builder . add_statement (parse_quote ! { # left_ident -> [0] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Difference (..) | HfPlusNode :: AntiJoin (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Difference (..)) { parse_quote ! (difference_multiset) } else { parse_quote ! (anti_join_multiset) } ; let (HfPlusNode :: Difference (left , right) | HfPlusNode :: AntiJoin (left , right)) = self else { unreachable ! () } ; let (right , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "difference / anti join inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; if right_was_persist { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } else { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } builder . add_statement (parse_quote ! { # left_ident -> [pos] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [neg] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Map { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let map_id = * next_stmt_id ; * next_stmt_id += 1 ; let map_ident = syn :: Ident :: new (& format ! ("stream_{}" , map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # map_ident = # input_ident -> map (# f) ; }) ; (map_ident , input_location_id) } HfPlusNode :: FlatMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let flat_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let flat_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , flat_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # flat_map_ident = # input_ident -> flat_map (# f) ; }) ; (flat_map_ident , input_location_id) } HfPlusNode :: Filter { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_ident = # input_ident -> filter (# f) ; }) ; (filter_ident , input_location_id) } HfPlusNode :: FilterMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_map_ident = # input_ident -> filter_map (# f) ; }) ; (filter_map_ident , input_location_id) } HfPlusNode :: Sort (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sort_id = * next_stmt_id ; * next_stmt_id += 1 ; let sort_ident = syn :: Ident :: new (& format ! ("stream_{}" , sort_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # sort_ident = # input_ident -> sort () ; }) ; (sort_ident , input_location_id) } HfPlusNode :: DeferTick (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let defer_tick_id = * next_stmt_id ; * next_stmt_id += 1 ; let defer_tick_ident = syn :: Ident :: new (& format ! ("stream_{}" , defer_tick_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # defer_tick_ident = # input_ident -> defer_tick_lazy () ; }) ; (defer_tick_ident , input_location_id) } HfPlusNode :: Enumerate (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let enumerate_id = * next_stmt_id ; * next_stmt_id += 1 ; let enumerate_ident = syn :: Ident :: new (& format ! ("stream_{}" , enumerate_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # enumerate_ident = # input_ident -> enumerate () ; }) ; (enumerate_ident , input_location_id) } HfPlusNode :: Inspect { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let inspect_id = * next_stmt_id ; * next_stmt_id += 1 ; let inspect_ident = syn :: Ident :: new (& format ! ("stream_{}" , inspect_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # inspect_ident = # input_ident -> inspect (# f) ; }) ; (inspect_ident , input_location_id) } HfPlusNode :: Unique (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let unique_id = * next_stmt_id ; * next_stmt_id += 1 ; let unique_ident = syn :: Ident :: new (& format ! ("stream_{}" , unique_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # unique_ident = # input_ident -> unique ::<'tick > () ; }) ; (unique_ident , input_location_id) } HfPlusNode :: Fold { .. } | HfPlusNode :: FoldKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Fold { .. }) { parse_quote ! (fold) } else { parse_quote ! (fold_keyed) } ; let (HfPlusNode :: Fold { init , acc , input } | HfPlusNode :: FoldKeyed { init , acc , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let fold_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'static > (# init , # acc) ; }) ; } else { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'tick > (# init , # acc) ; }) ; } (fold_ident , input_location_id) } HfPlusNode :: Reduce { .. } | HfPlusNode :: ReduceKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Reduce { .. }) { parse_quote ! (reduce) } else { parse_quote ! (reduce_keyed) } ; let (HfPlusNode :: Reduce { f , input } | HfPlusNode :: ReduceKeyed { f , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let reduce_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'static > (# f) ; }) ; } else { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'tick > (# f) ; }) ; } (reduce_ident , input_location_id) } HfPlusNode :: Network { from_location : _ , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input , } => { let (sink_expr , source_expr , _connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { panic ! ("Expected the network to be finalized") } DebugInstantiate :: Finalized (sink , source , connect_fn) => { (sink , source , connect_fn) } } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sender_builder = graph_builders . entry (input_location_id) . or_default () ; if let Some (serialize_pipeline) = serialize_pipeline { sender_builder . add_statement (parse_quote ! { # input_ident -> # serialize_pipeline -> dest_sink (# sink_expr) ; }) ; } else { sender_builder . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink_expr) ; }) ; } let to_id = match to_location { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let receiver_builder = graph_builders . entry (* to_id) . or_default () ; let receiver_stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let receiver_stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , receiver_stream_id) , Span :: call_site ()) ; if let Some (deserialize_pipeline) = deserialize_pipeline { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) -> # deserialize_pipeline ; }) ; } else { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) ; }) ; } (receiver_stream_ident , * to_id) } } } } } pub mod persist_pullup { pub use std :: cell :: RefCell ; pub use std :: collections :: HashSet ; pub use std :: ops :: Deref ; pub use crate :: ir :: * ; pub fn persist_pullup_node < 'a > (node : & mut HfPlusNode < 'a > , seen_tees : & mut SeenTees < 'a > , persist_pulled_tees : & mut HashSet < * const RefCell < HfPlusNode < 'a > > > ,) { node . transform_children (| n , s | persist_pullup_node (n , s , persist_pulled_tees) , seen_tees ,) ; match node { HfPlusNode :: Unpersist (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Unpersist (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Delta (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Delta (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Tee { inner } => { if persist_pulled_tees . contains (& (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >)) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } else { let inner_borrow = inner . borrow () ; if let HfPlusNode :: Persist (_) = inner_borrow . deref () { drop (inner_borrow) ; persist_pulled_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >) ; if let HfPlusNode :: Persist (box behind_persist) = inner . replace (HfPlusNode :: Placeholder) { * inner . borrow_mut () = behind_persist ; } else { unreachable ! () } * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } } } HfPlusNode :: Map { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Map { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Map { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: FlatMap { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: FlatMap { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: FlatMap { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Filter { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Filter { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Filter { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Network { input : box HfPlusNode :: Persist (_) , .. } => { if let HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Union (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Union (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Union (left , right))) ; } else { unreachable ! () } } HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: CrossProduct (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,) ,)))) ; } else { unreachable ! () } } HfPlusNode :: Join (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Join (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: Join (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,))))) ; } else { unreachable ! () } } _ => { } } } pub fn persist_pullup (ir : Vec < HfPlusLeaf >) -> Vec < HfPlusLeaf > { let mut seen_tees = Default :: default () ; let mut persist_pulled_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| n , s | persist_pullup_node (n , s , & mut persist_pulled_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn persist_pullup_through_map () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } # [test] fn persist_pullup_behind_tee () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; let before_tee = flow . source_iter (& process , q ! (0 .. 10)) . tick_batch () . persist () ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } } } pub mod profiler { pub use std :: cell :: RefCell ; pub use hydroflow :: futures :: channel :: mpsc :: UnboundedSender ; pub use stageleft :: * ; pub use crate as hydroflow_plus ; pub use crate :: ir :: * ; pub use crate :: RuntimeContext ; pub fn increment_counter (count : & mut u64) { * count += 1 ; } pub fn quoted_any_fn < 'a , F : Fn (& usize) + 'a , Q : IntoQuotedMut < 'a , F > > (q : Q) -> Q { q } # [doc = " Add a profiling node before each node to count the cardinality of its input"] pub fn add_profiling_node < 'a > (node : & mut HfPlusNode < 'a > , _context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > , id : & mut u32 , seen_tees : & mut SeenTees < 'a > ,) { let my_id = * id ; * id += 1 ; node . transform_children (| node , seen_tees | { add_profiling_node (node , _context , counters , counter_queue , id , seen_tees) } , seen_tees ,) ; let orig_node = std :: mem :: replace (node , HfPlusNode :: Placeholder) ; * node = HfPlusNode :: Inspect { f : quoted_any_fn (q ! ({ counter_queue . borrow () . unbounded_send ((my_id as usize , counters . borrow () [my_id as usize])) . unwrap () ; counters . borrow_mut () [my_id as usize] = 0 ; move | _ | { hydroflow_plus :: profiler :: increment_counter (& mut counters . borrow_mut () [my_id as usize] ,) ; } })) . splice () . into () , input : Box :: new (orig_node) , } } # [doc = " Count the cardinality of each input and periodically output to a file"] pub fn profiling < 'a > (ir : Vec < HfPlusLeaf < 'a > > , context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > ,) -> Vec < HfPlusLeaf < 'a > > { let mut id = 0 ; let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | { add_profiling_node (node , context , counters , counter_queue , & mut id , seen_tees) } , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn profiler_wrapping_all_operators () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let runtime_context = flow . runtime_context () ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (& built . ir ()) ; let counters = RuntimeData :: new ("Fake") ; let counter_queue = RuntimeData :: new ("Fake") ; let pushed_down = built . with_default_optimize () . optimize_with (| ir | super :: profiling (ir , runtime_context , counters , counter_queue)) ; insta :: assert_debug_snapshot ! (& pushed_down . ir ()) ; let _ = pushed_down . compile_no_network :: < MultiGraph > () ; } } } pub mod properties { pub use std :: collections :: HashSet ; pub use stageleft :: * ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , SeenTees } ; pub use crate :: properties :: PropertyDatabase ; # [doc = " Allows us to convert the hydroflow datatype for folds to a binary operation for the algebra"] # [doc = " property tests."] # [allow (dead_code)] pub fn convert_hf_to_binary < I , A : Default , F : Fn (& mut A , I) > (f : F) -> impl Fn (I , I) -> A { move | a , b | { let mut acc = Default :: default () ; f (& mut acc , a) ; f (& mut acc , b) ; acc } } # [cfg (stageleft_macro)] impl PropertyDatabase { # [doc = " Tags the expression as commutative."] pub fn add_commutative_tag < 'a , I , A , F : Fn (& mut A , I) , Q : Quoted < 'a , F > + Clone > (& mut self , expr : Q ,) -> Q { let expr_clone = expr . clone () ; self . commutative . insert (expr_clone . splice ()) ; expr } pub fn is_tagged_commutative (& self , expr : & syn :: Expr) -> bool { self . commutative . contains (expr) } } pub fn properties_optimize_node < 'a > (node : & mut HfPlusNode < 'a > , db : & PropertyDatabase , seen_tees : & mut SeenTees < 'a > ,) { node . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , seen_tees ,) ; match node { HfPlusNode :: ReduceKeyed { f , .. } if db . is_tagged_commutative (& f . 0) => { dbg ! ("IDENTIFIED COMMUTATIVE OPTIMIZATION for {:?}" , & f) ; } _ => { } } } pub fn properties_optimize < 'a > (ir : Vec < HfPlusLeaf < 'a > > , db : & PropertyDatabase ,) -> Vec < HfPlusLeaf < 'a > > { let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use super :: * ; use crate :: deploy :: SingleProcessGraph ; use crate :: FlowBuilder ; # [test] fn test_property_database () { let mut db = PropertyDatabase :: default () ; assert ! (! db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; let _ = db . add_commutative_tag (q ! (| a : & mut i32 , b : i32 | * a += b)) ; assert ! (db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; } # [test] fn test_property_optimized () { let flow = FlowBuilder :: new () ; let mut database = PropertyDatabase :: default () ; let process = flow . process :: < () > () ; let counter_func = q ! (| count : & mut i32 , _ | * count += 1) ; let _ = database . add_commutative_tag (counter_func) ; flow . source_iter (& process , q ! (vec ! [])) . map (q ! (| string : String | (string , ()))) . tick_batch () . fold_keyed (q ! (|| 0) , counter_func) . all_ticks () . for_each (q ! (| (string , count) | println ! ("{}: {}" , string , count))) ; let built = flow . finalize () . optimize_with (| ir | properties_optimize (ir , & database)) . with_default_optimize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let _ = built . compile_no_network :: < SingleProcessGraph > () ; } } } pub use crate :: RuntimeContext ; # [cfg (stageleft_macro)] impl Copy for RuntimeContext < '_ > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Context > for RuntimeContext < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (quote ! (& context))) } } pub use crate :: HfCompiled ; # [cfg (stageleft_macro)] impl < 'a , ID > HfCompiled < 'a , ID > { pub fn hydroflow_ir (& self) -> & BTreeMap < usize , HydroflowGraph > { & self . hydroflow_ir } } # [cfg (stageleft_macro)] impl < 'a > HfCompiled < 'a , usize > { pub fn with_dynamic_id (self , id : impl Quoted < 'a , usize >) -> HfBuiltWithId < 'a > { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; let mut conditioned_tokens = None ; for (subgraph_id , flat_graph) in self . hydroflow_ir { let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; let my_extra_stmts = self . extra_stmts . get (& subgraph_id) . cloned () . unwrap_or_default () ; if let Some (conditioned_tokens) = conditioned_tokens . as_mut () { * conditioned_tokens = syn :: parse_quote ! { # conditioned_tokens else if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } } ; } else { conditioned_tokens = Some (syn :: parse_quote ! { if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } }) ; } } let conditioned_tokens : TokenStream = conditioned_tokens . unwrap () ; let id = id . splice () ; HfBuiltWithId { tokens : syn :: parse_quote ! ({ let __given_id = # id ; # conditioned_tokens else { panic ! ("Invalid node id: {}" , __given_id) ; } }) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfCompiled < 'a , () > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfCompiled < 'a , () > { fn to_tokens (mut self) -> (Option < TokenStream > , Option < TokenStream >) { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; if self . hydroflow_ir . len () != 1 { panic ! ("Expected exactly one subgraph in the Hydroflow IR") ; } let flat_graph = self . hydroflow_ir . remove (& 0) . unwrap () ; let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; (None , Some (tokens)) } } pub use crate :: HfBuiltWithId ; # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfBuiltWithId < 'a > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfBuiltWithId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (self . tokens)) } }
[INFO] [stdout] 1 + pub use std :: collections :: BTreeMap ; pub use std :: marker :: PhantomData ; pub use hydroflow :: scheduled :: context :: Context ; pub use hydroflow :: scheduled :: graph :: Hydroflow ; pub use hydroflow :: * ; pub use lang :: graph :: { partition_graph , HydroflowGraph } ; pub use proc_macro2 :: TokenStream ; pub use quote :: quote ; pub use stageleft :: runtime_support :: FreeVariable ; pub use stageleft :: Quoted ; pub mod runtime_support { pub use bincode ; } pub mod stream { pub use std :: cell :: RefCell ; pub use std :: hash :: Hash ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow :: bytes :: Bytes ; pub use hydroflow :: futures :: Sink ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: quote ; pub use serde :: de :: DeserializeOwned ; pub use serde :: Serialize ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use syn :: parse_quote ; pub use crate :: builder :: { ClusterIds , FlowLeaves } ; pub use crate :: cycle :: { CycleCollection , CycleComplete } ; pub use crate :: ir :: { DebugInstantiate , HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { CanSend , Location , LocationId } ; pub use crate :: { Cluster , Optional , Singleton } ; pub use crate :: stream :: Unbounded ; pub use crate :: stream :: Bounded ; pub use crate :: stream :: NoTick ; pub use crate :: stream :: Tick ; pub use crate :: stream :: Stream ; # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Stream { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Stream < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Stream { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , C , N > > ,) -> Stream < 'a , (T , O) , W , C , N > where O : Clone , { let other : Optional < 'a , O , Bounded , C , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn cross_product < O > (self , other : Stream < 'a , O , W , C , N >) -> Stream < 'a , (T , O) , W , C , N > where T : Clone , O : Clone , { if self . location_kind != other . location_kind { panic ! ("cross_product must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossProduct (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn union (self , other : Stream < 'a , T , W , C , N >) -> Stream < 'a , T , W , C , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn dest_sink < S : Unpin + Sink < T > + 'a > (self , sink : impl Quoted < 'a , S >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: DestSink { sink : sink . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn first (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } # [doc = " Allow this stream through if the other stream has elements, otherwise the output is empty."] pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } # [doc = " Allow this stream through if the other stream is empty, otherwise the output is empty."] pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn enumerate (self) -> Stream < 'a , (usize , T) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Enumerate (Box :: new (self . ir_node . into_inner ())) ,) } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn sort (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Ord , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Sort (Box :: new (self . ir_node . into_inner ())) ,) } pub fn count (self) -> Singleton < 'a , usize , Bounded , Tick , N > { self . fold (q ! (|| 0usize) , q ! (| count , _ | * count += 1)) } pub fn delta (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } pub fn unique (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Eq + Hash , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unique (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn tick_batch (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_prefix (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { self . tick_batch () . persist () } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn for_each < F : Fn (T) + 'a > (self , f : impl IntoQuotedMut < 'a , F >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: ForEach { input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , f : f . splice () . into () , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Unbounded , NoTick , N > { pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . tick_batch () . continue_if (samples . first ()) . all_ticks () } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Unbounded , NoTick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , C , N : Location > Stream < 'a , T , Bounded , C , N > { pub fn filter_not_in (self , other : Stream < 'a , T , Bounded , C , N >) -> Stream < 'a , T , Bounded , C , N > where T : Eq + Hash , { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Difference (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Stream < 'a , & T , W , C , N > { pub fn cloned (self) -> Stream < 'a , T , W , C , N > { self . map (q ! (| d | d . clone ())) } } # [cfg (stageleft_macro)] impl < 'a , K , V1 , W , C , N : Location > Stream < 'a , (K , V1) , W , C , N > { pub fn join < W2 , V2 > (self , n : Stream < 'a , (K , V2) , W2 , C , N > ,) -> Stream < 'a , (K , (V1 , V2)) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Join (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } pub fn anti_join < W2 > (self , n : Stream < 'a , K , W2 , C , N >) -> Stream < 'a , (K , V1) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("anti_join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: AntiJoin (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , K : Eq + Hash , V , N : Location > Stream < 'a , (K , V) , Bounded , Tick , N > { pub fn fold_keyed < A , I : Fn () -> A + 'a , F : Fn (& mut A , V) + 'a > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , A) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FoldKeyed { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce_keyed < F : Fn (& mut V , V) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , V) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: ReduceKeyed { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } pub fn get_this_crate () -> TokenStream { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , Span :: call_site ()) ; quote ! { # ident } } } } pub fn serialize_bincode < T : Serialize > (is_demux : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if is_demux { parse_quote ! { map (| (id , data) | { (id , # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into ()) }) } } else { parse_quote ! { map (| data | { # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into () }) } } } pub fn deserialize_bincode < T : DeserializeOwned > (tagged : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if tagged { parse_quote ! { map (| res | { let (id , b) = res . unwrap () ; (id , # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& b) . unwrap ()) }) } } else { parse_quote ! { map (| res | { # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& res . unwrap ()) . unwrap () }) } } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn send_bincode < N2 : Location , CoreType > (self , other : & N2 ,) -> Stream < 'a , N :: Out < CoreType > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T > , CoreType : Serialize + DeserializeOwned , { let serialize_pipeline = Some (serialize_bincode :: < CoreType > (N :: is_demux ())) ; let deserialize_pipeline = Some (deserialize_bincode :: < CoreType > (N :: is_tagged ())) ; Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bytes < N2 : Location > (self , other : & N2 ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T > , { Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline : None , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline : if N :: is_tagged () { Some (parse_quote ! (map (| (id , b) | (id , b . unwrap () . freeze ())))) } else { Some (parse_quote ! (map (| b | b . unwrap () . freeze ()))) } , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bincode_interleaved < N2 : Location , Tag , CoreType > (self , other : & N2 ,) -> Stream < 'a , CoreType , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T , Out < CoreType > = (Tag , CoreType) > , CoreType : Serialize + DeserializeOwned , { self . send_bincode :: < N2 , CoreType > (other) . map (q ! (| (_ , b) | b)) } pub fn send_bytes_interleaved < N2 : Location , Tag > (self , other : & N2 ,) -> Stream < 'a , Bytes , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T , Out < Bytes > = (Tag , Bytes) > , { self . send_bytes :: < N2 > (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bincode < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < T > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) > , T : Clone + Serialize + DeserializeOwned , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bincode (other) } pub fn broadcast_bincode_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , T , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) , Out < T > = (Tag , T) > + 'a , T : Clone + Serialize + DeserializeOwned , { self . broadcast_bincode (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bytes < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) > + 'a , T : Clone , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bytes (other) } pub fn broadcast_bytes_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , Bytes , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) , Out < Bytes > = (Tag , Bytes) > + 'a , T : Clone , { self . broadcast_bytes (other) . map (q ! (| (_ , b) | b)) } } } pub use stream :: { Bounded , NoTick , Stream , Tick , Unbounded } ; pub mod singleton { pub use std :: cell :: RefCell ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use crate :: builder :: FlowLeaves ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial , CycleComplete } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: Stream ; pub use crate :: singleton :: CrossResult ; # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Singleton < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Singleton :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } pub use crate :: singleton :: Singleton ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Singleton { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleComplete < 'a > for Singleton < 'a , T , Bounded , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleCollectionWithInitial < 'a > for Singleton < 'a , T , Bounded , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , initial : Self , l : LocationId ,) -> Self { Singleton :: new (l , ir_leaves , HfPlusNode :: Union (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , }) , initial . ir_node . into_inner () . into () ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Singleton < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Singleton { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , U , W , C , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (Self :: other_ir_node (other)) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Singleton < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CrossSingleton (Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , Box :: new (HfPlusNode :: Unpersist (Box :: new (Self :: other_ir_node (other)))) ,))) ,) } } pub use crate :: singleton :: Optional ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Optional { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } pub fn some (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: new (singleton . location_kind , singleton . ir_leaves , singleton . ir_node . into_inner () ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > From < Singleton < 'a , T , W , C , N > > for Optional < 'a , T , W , C , N > { fn from (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: some (singleton) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Optional < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Optional { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn into_stream (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , Tick , N > > ,) -> Optional < 'a , (T , O) , Bounded , Tick , N > where O : Clone , { let other : Optional < 'a , O , Bounded , Tick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn union (self , other : Optional < 'a , T , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Optional < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_samples (self) -> Stream < 'a , T , Unbounded , NoTick , N > { self . latest_tick () . all_ticks () } pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . latest_tick () . continue_if (samples . first ()) . latest () . tick_samples () } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Unbounded , NoTick , N > > ,) -> Optional < 'a , (T , O) , Unbounded , NoTick , N > where O : Clone , { let other : Optional < 'a , O , Unbounded , NoTick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } self . latest_tick () . cross_singleton (other . latest_tick ()) . latest () } } } pub use singleton :: { Optional , Singleton } ; pub mod location { pub use std :: marker :: PhantomData ; pub use crate :: location :: LocationId ; pub use crate :: location :: Location ; pub use crate :: location :: Process ; # [cfg (stageleft_macro)] impl < P > Clone for Process < P > { fn clone (& self) -> Self { Process { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < P > Location for Process < P > { fn id (& self) -> LocationId { LocationId :: Process (self . id) } } pub use crate :: location :: Cluster ; # [cfg (stageleft_macro)] impl < C > Clone for Cluster < C > { fn clone (& self) -> Self { Cluster { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < C > Location for Cluster < C > { fn id (& self) -> LocationId { LocationId :: Cluster (self . id) } } pub use crate :: location :: CanSend ; # [cfg (stageleft_macro)] impl < P1 , P2 > CanSend < Process < P2 > > for Process < P1 > { type In < T > = T ; type Out < T > = T ; fn is_demux () -> bool { false } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < P1 , C2 > CanSend < Cluster < C2 > > for Process < P1 > { type In < T > = (u32 , T) ; type Out < T > = T ; fn is_demux () -> bool { true } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < C1 , P2 > CanSend < Process < P2 > > for Cluster < C1 > { type In < T > = T ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { false } fn is_tagged () -> bool { true } } # [cfg (stageleft_macro)] impl < C1 , C2 > CanSend < Cluster < C2 > > for Cluster < C1 > { type In < T > = (u32 , T) ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { true } fn is_tagged () -> bool { true } } } pub use location :: { Cluster , Process } ; pub mod deploy { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use stageleft :: Quoted ; pub mod graphs { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use super :: { LocalDeploy , Node , ProcessSpec } ; pub use crate :: deploy :: graphs :: SingleProcessGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for SingleProcessGraph { type Process = SingleNode ; type Cluster = SingleNode ; type Meta = () ; type GraphId = () ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { SingleNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { SingleNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , SingleProcessGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> SingleNode { SingleNode { } } } pub use crate :: deploy :: graphs :: SingleNode ; # [cfg (stageleft_macro)] impl Node for SingleNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } pub use crate :: deploy :: graphs :: MultiGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for MultiGraph { type Process = MultiNode ; type Cluster = MultiNode ; type Meta = () ; type GraphId = usize ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { MultiNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { MultiNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , MultiGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> MultiNode { MultiNode { } } } pub use crate :: deploy :: graphs :: MultiNode ; # [cfg (stageleft_macro)] impl Node for MultiNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } } pub use graphs :: * ; pub use crate :: deploy :: LocalDeploy ; pub use crate :: deploy :: Deploy ; # [cfg (stageleft_macro)] impl < 'a , T : Deploy < 'a , Process = N , Cluster = C , Meta = M , GraphId = R > , N : Node < Meta = M > , C : Node < Meta = M > , M : Default , R , > LocalDeploy < 'a > for T { type Process = N ; type Cluster = C ; type Meta = M ; type GraphId = R ; fn has_trivial_node () -> bool { < T as Deploy < 'a > > :: has_trivial_node () } fn trivial_process (id : usize) -> Self :: Process { < T as Deploy < 'a > > :: trivial_process (id) } fn trivial_cluster (id : usize) -> Self :: Cluster { < T as Deploy < 'a > > :: trivail_cluster (id) } } pub use crate :: deploy :: ProcessSpec ; pub use crate :: deploy :: ClusterSpec ; pub use crate :: deploy :: Node ; } pub use deploy :: { ClusterSpec , Deploy , ProcessSpec } ; pub mod cycle { pub use std :: marker :: PhantomData ; pub use crate :: builder :: FlowLeaves ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: cycle :: CycleComplete ; pub use crate :: cycle :: CycleCollection ; pub use crate :: cycle :: CycleCollectionWithInitial ; pub use crate :: cycle :: HfCycle ; # [cfg (stageleft_macro)] impl < 'a , S : CycleComplete < 'a > > HfCycle < 'a , S > { pub fn complete (self , stream : S) { let ident = self . ident ; S :: complete (stream , ident) } } } pub use cycle :: HfCycle ; pub mod builder { pub use std :: cell :: RefCell ; pub use std :: collections :: HashMap ; pub use std :: marker :: PhantomData ; pub use std :: rc :: Rc ; pub use std :: time :: Duration ; pub use hydroflow :: futures :: stream :: Stream as FuturesStream ; pub use hydroflow :: { tokio , tokio_stream } ; pub use internal :: TokenStream ; pub use proc_macro2 :: Span ; pub use quote :: quote ; pub use runtime_support :: FreeVariable ; pub use stageleft :: * ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Cluster , Location , LocationId , Process } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: { HfCycle , Optional , RuntimeContext , Singleton , Stream } ; pub mod built { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use hydroflow_lang :: graph :: { eliminate_extra_unions_tees , HydroflowGraph } ; pub use super :: deploy :: { DeployFlow , DeployResult } ; pub use crate :: deploy :: { ClusterSpec , Deploy , LocalDeploy , ProcessSpec } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Cluster , Process } ; pub use crate :: HfCompiled ; pub use crate :: builder :: built :: BuiltFlow ; # [cfg (stageleft_macro)] impl < 'a > Drop for BuiltFlow < 'a > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped BuiltFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn ir (& self) -> & Vec < HfPlusLeaf < 'a > > { & self . ir } pub fn optimize_with (mut self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> BuiltFlow < 'a > { self . used = true ; BuiltFlow { ir : f (std :: mem :: take (& mut self . ir)) , processes : std :: mem :: take (& mut self . processes) , clusters : std :: mem :: take (& mut self . clusters) , used : false , _phantom : PhantomData , } } } pub fn build_inner (ir : & mut Vec < HfPlusLeaf >) -> BTreeMap < usize , HydroflowGraph > { let mut builders = BTreeMap :: new () ; let mut built_tees = HashMap :: new () ; let mut next_stmt_id = 0 ; for leaf in ir { leaf . emit (& mut builders , & mut built_tees , & mut next_stmt_id) ; } builders . into_iter () . map (| (k , v) | { let (mut flat_graph , _ , _) = v . build () ; eliminate_extra_unions_tees (& mut flat_graph) ; (k , flat_graph) }) . collect () } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn compile_no_network < D : LocalDeploy < 'a > > (mut self) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; HfCompiled { hydroflow_ir : build_inner (& mut self . ir) , extra_stmts : BTreeMap :: new () , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> BuiltFlow < 'a > { self . optimize_with (crate :: persist_pullup :: persist_pullup) } fn into_deploy < D : LocalDeploy < 'a > > (mut self) -> DeployFlow < 'a , D > { self . used = true ; let processes = if D :: has_trivial_node () { self . processes . iter () . map (| id | (* id , D :: trivial_process (* id))) . collect () } else { HashMap :: new () } ; let clusters = if D :: has_trivial_node () { self . clusters . iter () . map (| id | (* id , D :: trivial_cluster (* id))) . collect () } else { HashMap :: new () } ; DeployFlow { ir : std :: mem :: take (& mut self . ir) , nodes : processes , clusters , used : false , _phantom : PhantomData , } } pub fn with_process < P , D : LocalDeploy < 'a > > (self , process : & Process < P > , spec : impl ProcessSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_process (process , spec) } pub fn with_cluster < C , D : LocalDeploy < 'a > > (self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_cluster (cluster , spec) } pub fn compile < D : Deploy < 'a > + 'a > (self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . into_deploy :: < D > () . compile (env) } pub fn deploy < D : Deploy < 'a , CompileEnv = () > + 'a > (self , env : & mut D :: InstantiateEnv ,) -> DeployResult < 'a , D > { self . into_deploy :: < D > () . deploy (env) } } } pub mod deploy { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use proc_macro2 :: Span ; pub use stageleft :: Quoted ; pub use super :: built :: build_inner ; pub use crate :: deploy :: { LocalDeploy , Node } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: { Cluster , ClusterSpec , Deploy , HfCompiled , Process , ProcessSpec } ; pub use crate :: builder :: deploy :: DeployFlow ; # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > Drop for DeployFlow < 'a , D > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped DeployFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > DeployFlow < 'a , D > { pub fn with_process < P > (mut self , process : & Process < P > , spec : impl ProcessSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < P > () . to_string () ; self . nodes . insert (process . id , spec . build (process . id , & tag_name)) ; self } pub fn with_cluster < C > (mut self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < C > () . to_string () ; self . clusters . insert (cluster . id , spec . build (cluster . id , & tag_name)) ; self } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployFlow < 'a , D > { pub fn compile (mut self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; let mut seen_tees : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | leaf . compile_network :: < D > (env , & mut seen_tees , & self . nodes , & self . clusters)) . collect () ; let extra_stmts = self . extra_stmts (env) ; HfCompiled { hydroflow_ir : build_inner (& mut ir_leaves_networked) , extra_stmts , _phantom : PhantomData , } } fn extra_stmts (& self , env : & < D as Deploy < 'a > > :: CompileEnv) -> BTreeMap < usize , Vec < syn :: Stmt > > { let all_locations_count = self . nodes . len () + self . clusters . len () ; let mut extra_stmts : BTreeMap < usize , Vec < syn :: Stmt > > = BTreeMap :: new () ; for & c_id in self . clusters . keys () { let self_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , c_id) , Span :: call_site () ,) ; let self_id_expr = D :: cluster_self_id (env) . splice () ; extra_stmts . entry (c_id) . or_default () . push (syn :: parse_quote ! { let # self_id_ident = # self_id_expr ; }) ; for other_location in 0 .. all_locations_count { let other_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , c_id) , Span :: call_site () ,) ; let other_id_expr = D :: cluster_ids (env , c_id) . splice () ; extra_stmts . entry (other_location) . or_default () . push (syn :: parse_quote ! { let # other_id_ident = # other_id_expr ; }) ; } } extra_stmts } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a , CompileEnv = () > > DeployFlow < 'a , D > { # [must_use] pub fn deploy (mut self , env : & mut D :: InstantiateEnv) -> DeployResult < 'a , D > { self . used = true ; let mut seen_tees_instantiate : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | { leaf . compile_network :: < D > (& () , & mut seen_tees_instantiate , & self . nodes , & self . clusters ,) }) . collect () ; let mut compiled = build_inner (& mut ir_leaves_networked) ; let mut extra_stmts = self . extra_stmts (& ()) ; let mut meta = D :: Meta :: default () ; let (mut processes , mut clusters) = (std :: mem :: take (& mut self . nodes) . into_iter () . map (| (node_id , node) | { node . instantiate (env , & mut meta , compiled . remove (& node_id) . unwrap () , extra_stmts . remove (& node_id) . unwrap_or_default () ,) ; (node_id , node) }) . collect :: < HashMap < _ , _ > > () , std :: mem :: take (& mut self . clusters) . into_iter () . map (| (cluster_id , cluster) | { cluster . instantiate (env , & mut meta , compiled . remove (& cluster_id) . unwrap () , extra_stmts . remove (& cluster_id) . unwrap_or_default () ,) ; (cluster_id , cluster) }) . collect :: < HashMap < _ , _ > > () ,) ; for node in processes . values_mut () { node . update_meta (& meta) ; } for cluster in clusters . values_mut () { cluster . update_meta (& meta) ; } let mut seen_tees_connect = HashMap :: new () ; for leaf in ir_leaves_networked { leaf . connect_network (& mut seen_tees_connect) ; } DeployResult { processes , clusters , } } } pub use crate :: builder :: deploy :: DeployResult ; # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployResult < 'a , D > { pub fn get_process < P > (& self , p : & Process < P >) -> & D :: Process { let id = match p . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . processes . get (& id) . unwrap () } pub fn get_cluster < C > (& self , c : & Cluster < C >) -> & D :: Cluster { let id = match c . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . clusters . get (& id) . unwrap () } } } # [doc = " Tracks the leaves of the dataflow IR. This is referenced by"] # [doc = " `Stream` and `HfCycle` to build the IR. The inner option will"] # [doc = " be set to `None` when this builder is finalized."] pub type FlowLeaves < 'a > = Rc < RefCell < Option < Vec < HfPlusLeaf < 'a > > > > > ; pub use crate :: builder :: ClusterIds ; # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Vec < u32 > > for ClusterIds < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , & 'a Vec < u32 > > for ClusterIds < 'a > { } # [derive (Copy , Clone)] pub struct ClusterSelfId < 'a > { pub id : usize , pub _phantom : PhantomData < & 'a mut & 'a u32 > , } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < u32 > for ClusterSelfId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , u32 > for ClusterSelfId < 'a > { } pub use crate :: builder :: FlowBuilder ; # [cfg (stageleft_macro)] impl < 'a > Drop for FlowBuilder < 'a > { fn drop (& mut self) { if ! self . finalized { panic ! ("Dropped FlowBuilder without finalizing, you may have forgotten to call `with_default_optimize`, `optimize_with`, or `finalize`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > QuotedContext for FlowBuilder < 'a > { fn create () -> Self { FlowBuilder :: new () } } # [cfg (stageleft_macro)] impl < 'a > FlowBuilder < 'a > { # [allow (clippy :: new_without_default)] pub fn new () -> FlowBuilder < 'a > { FlowBuilder { ir_leaves : Rc :: new (RefCell :: new (Some (Vec :: new ()))) , nodes : RefCell :: new (vec ! []) , clusters : RefCell :: new (vec ! []) , cycle_ids : RefCell :: new (HashMap :: new ()) , next_node_id : RefCell :: new (0) , finalized : false , _phantom : PhantomData , } } pub fn finalize (mut self) -> built :: BuiltFlow < 'a > { self . finalized = true ; built :: BuiltFlow { ir : self . ir_leaves . borrow_mut () . take () . unwrap () , processes : self . nodes . replace (vec ! []) , clusters : self . clusters . replace (vec ! []) , used : false , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> built :: BuiltFlow < 'a > { self . finalize () . with_default_optimize () } pub fn optimize_with (self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> built :: BuiltFlow < 'a > { self . finalize () . optimize_with (f) } pub fn ir_leaves (& self) -> & FlowLeaves < 'a > { & self . ir_leaves } pub fn process < P > (& self) -> Process < P > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . nodes . borrow_mut () . push (id) ; Process { id , _phantom : PhantomData , } } pub fn cluster < C > (& self) -> Cluster < C > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . clusters . borrow_mut () . push (id) ; Cluster { id , _phantom : PhantomData , } } pub fn runtime_context (& self) -> RuntimeContext < 'a > { RuntimeContext { _phantom : PhantomData , } } pub fn cluster_members < C > (& self , cluster : & Cluster < C > ,) -> impl Quoted < 'a , & 'a Vec < u32 > > + Copy + 'a { ClusterIds { id : cluster . id , _phantom : PhantomData , } } pub fn cluster_self_id < C > (& self , cluster : & Cluster < C >) -> impl Quoted < 'a , u32 > + Copy + 'a { ClusterSelfId { id : cluster . id , _phantom : PhantomData , } } pub fn spin < L : Location > (& self , on : & L) -> Stream < 'a , () , Unbounded , NoTick , L > { Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Spin () , location_kind : on . id () , })) ,) } pub fn spin_batch < L : Location > (& self , on : & L , batch_size : impl Quoted < 'a , usize > + Copy + 'a ,) -> Stream < 'a , () , Bounded , Tick , L > { self . spin (on) . flat_map (q ! (move | _ | 0 .. batch_size)) . map (q ! (| _ | ())) . tick_batch () } pub fn source_stream < T , E : FuturesStream < Item = T > + Unpin , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Unbounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Stream (e . into ()) , location_kind : on . id () , })) ,) } pub fn source_iter < T , E : IntoIterator < Item = T > , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Bounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , })) ,) } pub fn singleton < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Singleton < 'a , T , Bounded , NoTick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Singleton :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,)))) ,) } pub fn singleton_first_tick < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Optional < 'a , T , Bounded , Tick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,) } pub fn source_interval < L : Location > (& self , on : & L , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , () , Unbounded , NoTick , L > { let interval = interval . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : on . id () , })) ,) } pub fn source_interval_delayed < L : Location > (& self , on : & L , delay : impl Quoted < 'a , Duration > + Copy + 'a , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , tokio :: time :: Instant , Unbounded , NoTick , L > { self . source_stream (on , q ! (tokio_stream :: wrappers :: IntervalStream :: new (tokio :: time :: interval_at (tokio :: time :: Instant :: now () + delay , interval))) ,) . tick_batch () . first () . latest () } pub fn cycle < S : CycleCollection < 'a > > (& self , on : & S :: Location) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , on . id ()) ,) } pub fn cycle_with_initial < S : CycleCollectionWithInitial < 'a > > (& self , on : & S :: Location , initial : S ,) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , initial , on . id ()) ,) } } } pub use builder :: FlowBuilder ; pub mod ir { pub use core :: panic ; pub use std :: cell :: RefCell ; pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow_lang :: graph :: FlatGraphBuilder ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: ToTokens ; pub use syn :: parse_quote ; pub use crate :: deploy :: Deploy ; pub use crate :: location :: LocationId ; pub use crate :: ir :: DebugExpr ; # [cfg (stageleft_macro)] impl From < syn :: Expr > for DebugExpr { fn from (expr : syn :: Expr) -> DebugExpr { DebugExpr (expr) } } # [cfg (stageleft_macro)] impl Deref for DebugExpr { type Target = syn :: Expr ; fn deref (& self) -> & Self :: Target { & self . 0 } } # [cfg (stageleft_macro)] impl ToTokens for DebugExpr { fn to_tokens (& self , tokens : & mut TokenStream) { self . 0 . to_tokens (tokens) ; } } # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugExpr { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "{}" , self . 0 . to_token_stream ()) } } pub use crate :: ir :: DebugInstantiate ; # [cfg (stageleft_macro)] impl < 'a > std :: fmt :: Debug for DebugInstantiate < 'a > { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<network instantiate>") } } pub use crate :: ir :: DebugPipelineFn ; # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugPipelineFn { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<function>") } } pub use crate :: ir :: HfPlusSource ; pub use crate :: ir :: HfPlusLeaf ; # [cfg (stageleft_macro)] impl < 'a > HfPlusLeaf < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . compile_network :: < D > (compile_env , s , nodes , clusters) ; } , seen_tees ,) } pub fn connect_network (self , seen_tees : & mut SeenTees < 'a >) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . connect_network (s) ; } , seen_tees ,) } pub fn transform_children (self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) -> HfPlusLeaf < 'a > { match self { HfPlusLeaf :: ForEach { f , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: ForEach { f , input } } HfPlusLeaf :: DestSink { sink , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: DestSink { sink , input } } HfPlusLeaf :: CycleSink { ident , location_kind , mut input , } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: CycleSink { ident , location_kind , input , } } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) { match self { HfPlusLeaf :: ForEach { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> for_each (# f) ; }) ; } HfPlusLeaf :: DestSink { sink , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink) ; }) ; } HfPlusLeaf :: CycleSink { ident , location_kind , input , } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; assert_eq ! (input_location_id , * location_id , "cycle_sink location mismatch") ; graph_builders . entry (* location_id) . or_default () . add_statement (parse_quote ! { # ident = # input_ident ; }) ; } } } } pub use crate :: ir :: HfPlusNode ; pub type SeenTees < 'a > = HashMap < * const RefCell < HfPlusNode < 'a > > , Rc < RefCell < HfPlusNode < 'a > > > > ; # [cfg (stageleft_macro)] impl < 'a > HfPlusNode < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (& mut self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) { self . transform_children (| n , s | n . compile_network :: < D > (compile_env , s , nodes , clusters) , seen_tees ,) ; if let HfPlusNode :: Network { from_location , to_location , instantiate_fn , .. } = self { let (sink_expr , source_expr , connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { let ((sink , source) , connect_fn) = match (from_location , to_location) { (LocationId :: Process (from) , LocationId :: Process (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: o2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Process (from) , LocationId :: Cluster (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: o2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Process (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: m2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Cluster (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: m2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } } ; (sink , source , connect_fn) } DebugInstantiate :: Finalized (_ , _ , _) => panic ! ("network already finalized") , } ; * instantiate_fn = DebugInstantiate :: Finalized (sink_expr , source_expr , connect_fn) ; } } pub fn connect_network (& mut self , seen_tees : & mut SeenTees < 'a >) { self . transform_children (| n , s | n . connect_network (s) , seen_tees) ; if let HfPlusNode :: Network { instantiate_fn , .. } = self { match instantiate_fn { DebugInstantiate :: Building () => panic ! ("network not built") , DebugInstantiate :: Finalized (_ , _ , ref connect_fn) => { connect_fn () ; } } } } pub fn transform_children (& mut self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) { match self { HfPlusNode :: Placeholder => { panic ! () ; } HfPlusNode :: Source { .. } => { } HfPlusNode :: CycleSource { .. } => { } HfPlusNode :: Tee { inner } => { if let Some (transformed) = seen_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { * inner = transformed . clone () ; } else { let transformed_cell = Rc :: new (RefCell :: new (HfPlusNode :: Placeholder)) ; seen_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , transformed_cell . clone () ,) ; let mut orig = inner . replace (HfPlusNode :: Placeholder) ; transform (& mut orig , seen_tees) ; * transformed_cell . borrow_mut () = orig ; * inner = transformed_cell ; } } HfPlusNode :: Persist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Unpersist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Delta (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Union (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossProduct (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossSingleton (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Join (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Difference (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: AntiJoin (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Map { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FlatMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Filter { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FilterMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Sort (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: DeferTick (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Enumerate (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Inspect { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Unique (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Fold { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FoldKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Reduce { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: ReduceKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Network { input , .. } => { transform (input . as_mut () , seen_tees) ; } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) -> (syn :: Ident , usize) { match self { HfPlusNode :: Placeholder => { panic ! () } HfPlusNode :: Persist (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let persist_id = * next_stmt_id ; * next_stmt_id += 1 ; let persist_ident = syn :: Ident :: new (& format ! ("stream_{}" , persist_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # persist_ident = # inner_ident -> persist ::<'static > () ; }) ; (persist_ident , location) } HfPlusNode :: Unpersist (_) => { panic ! ("Unpersist is a marker node and should have been optimized away. This is likely a compiler bug.") } HfPlusNode :: Delta (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let delta_id = * next_stmt_id ; * next_stmt_id += 1 ; let delta_ident = syn :: Ident :: new (& format ! ("stream_{}" , delta_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # delta_ident = # inner_ident -> multiset_delta () ; }) ; (delta_ident , location) } HfPlusNode :: Source { source , location_kind , } => { let source_id = * next_stmt_id ; * next_stmt_id += 1 ; let source_ident = syn :: Ident :: new (& format ! ("stream_{}" , source_id) , Span :: call_site ()) ; let source_stmt = match source { HfPlusSource :: Stream (expr) => { parse_quote ! { # source_ident = source_stream (# expr) ; } } HfPlusSource :: Iter (expr) => { parse_quote ! { # source_ident = source_iter (# expr) ; } } HfPlusSource :: Interval (expr) => { parse_quote ! { # source_ident = source_interval (# expr) ; } } HfPlusSource :: Spin () => { parse_quote ! { # source_ident = spin () ; } } } ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; graph_builders . entry (* location_id) . or_default () . add_statement (source_stmt) ; (source_ident , * location_id) } HfPlusNode :: CycleSource { ident , location_kind , } => { let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; (ident . clone () , * location_id) } HfPlusNode :: Tee { inner } => { if let Some (ret) = built_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { ret . clone () } else { let (inner_ident , inner_location_id) = inner . borrow () . emit (graph_builders , built_tees , next_stmt_id) ; let tee_id = * next_stmt_id ; * next_stmt_id += 1 ; let tee_ident = syn :: Ident :: new (& format ! ("stream_{}" , tee_id) , Span :: call_site ()) ; let builder = graph_builders . entry (inner_location_id) . or_default () ; builder . add_statement (parse_quote ! { # tee_ident = # inner_ident -> tee () ; }) ; built_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , (tee_ident . clone () , inner_location_id) ,) ; (tee_ident , inner_location_id) } } HfPlusNode :: Union (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "union inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let union_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # union_ident = union () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [0] # union_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # union_ident ; }) ; (union_ident , left_location_id) } HfPlusNode :: CrossSingleton (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "cross_singleton inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let cross_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # cross_ident = cross_singleton () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [input] # cross_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [single] # cross_ident ; }) ; (cross_ident , left_location_id) } HfPlusNode :: CrossProduct (..) | HfPlusNode :: Join (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: CrossProduct (..)) { parse_quote ! (cross_join_multiset) } else { parse_quote ! (join_multiset) } ; let (HfPlusNode :: CrossProduct (left , right) | HfPlusNode :: Join (left , right)) = self else { unreachable ! () } ; let (left_inner , left_was_persist) = if let HfPlusNode :: Persist (left) = left . as_ref () { (left , true) } else { (left , false) } ; let (right_inner , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left_inner . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right_inner . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "join / cross product inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; match (left_was_persist , right_was_persist) { (true , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'static > () ; }) ; } (true , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'tick > () ; }) ; } (false , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } (false , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } } ; builder . add_statement (parse_quote ! { # left_ident -> [0] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Difference (..) | HfPlusNode :: AntiJoin (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Difference (..)) { parse_quote ! (difference_multiset) } else { parse_quote ! (anti_join_multiset) } ; let (HfPlusNode :: Difference (left , right) | HfPlusNode :: AntiJoin (left , right)) = self else { unreachable ! () } ; let (right , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "difference / anti join inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; if right_was_persist { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } else { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } builder . add_statement (parse_quote ! { # left_ident -> [pos] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [neg] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Map { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let map_id = * next_stmt_id ; * next_stmt_id += 1 ; let map_ident = syn :: Ident :: new (& format ! ("stream_{}" , map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # map_ident = # input_ident -> map (# f) ; }) ; (map_ident , input_location_id) } HfPlusNode :: FlatMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let flat_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let flat_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , flat_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # flat_map_ident = # input_ident -> flat_map (# f) ; }) ; (flat_map_ident , input_location_id) } HfPlusNode :: Filter { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_ident = # input_ident -> filter (# f) ; }) ; (filter_ident , input_location_id) } HfPlusNode :: FilterMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_map_ident = # input_ident -> filter_map (# f) ; }) ; (filter_map_ident , input_location_id) } HfPlusNode :: Sort (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sort_id = * next_stmt_id ; * next_stmt_id += 1 ; let sort_ident = syn :: Ident :: new (& format ! ("stream_{}" , sort_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # sort_ident = # input_ident -> sort () ; }) ; (sort_ident , input_location_id) } HfPlusNode :: DeferTick (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let defer_tick_id = * next_stmt_id ; * next_stmt_id += 1 ; let defer_tick_ident = syn :: Ident :: new (& format ! ("stream_{}" , defer_tick_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # defer_tick_ident = # input_ident -> defer_tick_lazy () ; }) ; (defer_tick_ident , input_location_id) } HfPlusNode :: Enumerate (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let enumerate_id = * next_stmt_id ; * next_stmt_id += 1 ; let enumerate_ident = syn :: Ident :: new (& format ! ("stream_{}" , enumerate_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # enumerate_ident = # input_ident -> enumerate () ; }) ; (enumerate_ident , input_location_id) } HfPlusNode :: Inspect { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let inspect_id = * next_stmt_id ; * next_stmt_id += 1 ; let inspect_ident = syn :: Ident :: new (& format ! ("stream_{}" , inspect_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # inspect_ident = # input_ident -> inspect (# f) ; }) ; (inspect_ident , input_location_id) } HfPlusNode :: Unique (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let unique_id = * next_stmt_id ; * next_stmt_id += 1 ; let unique_ident = syn :: Ident :: new (& format ! ("stream_{}" , unique_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # unique_ident = # input_ident -> unique ::<'tick > () ; }) ; (unique_ident , input_location_id) } HfPlusNode :: Fold { .. } | HfPlusNode :: FoldKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Fold { .. }) { parse_quote ! (fold) } else { parse_quote ! (fold_keyed) } ; let (HfPlusNode :: Fold { init , acc , input } | HfPlusNode :: FoldKeyed { init , acc , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let fold_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'static > (# init , # acc) ; }) ; } else { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'tick > (# init , # acc) ; }) ; } (fold_ident , input_location_id) } HfPlusNode :: Reduce { .. } | HfPlusNode :: ReduceKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Reduce { .. }) { parse_quote ! (reduce) } else { parse_quote ! (reduce_keyed) } ; let (HfPlusNode :: Reduce { f , input } | HfPlusNode :: ReduceKeyed { f , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let reduce_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'static > (# f) ; }) ; } else { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'tick > (# f) ; }) ; } (reduce_ident , input_location_id) } HfPlusNode :: Network { from_location : _ , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input , } => { let (sink_expr , source_expr , _connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { panic ! ("Expected the network to be finalized") } DebugInstantiate :: Finalized (sink , source , connect_fn) => { (sink , source , connect_fn) } } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sender_builder = graph_builders . entry (input_location_id) . or_default () ; if let Some (serialize_pipeline) = serialize_pipeline { sender_builder . add_statement (parse_quote ! { # input_ident -> # serialize_pipeline -> dest_sink (# sink_expr) ; }) ; } else { sender_builder . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink_expr) ; }) ; } let to_id = match to_location { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let receiver_builder = graph_builders . entry (* to_id) . or_default () ; let receiver_stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let receiver_stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , receiver_stream_id) , Span :: call_site ()) ; if let Some (deserialize_pipeline) = deserialize_pipeline { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) -> # deserialize_pipeline ; }) ; } else { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) ; }) ; } (receiver_stream_ident , * to_id) } } } } } pub mod persist_pullup { pub use std :: cell :: RefCell ; pub use std :: collections :: HashSet ; pub use std :: ops :: Deref ; pub use crate :: ir :: * ; pub fn persist_pullup_node < 'a > (node : & mut HfPlusNode < 'a > , seen_tees : & mut SeenTees < 'a > , persist_pulled_tees : & mut HashSet < * const RefCell < HfPlusNode < 'a > > > ,) { node . transform_children (| n , s | persist_pullup_node (n , s , persist_pulled_tees) , seen_tees ,) ; match node { HfPlusNode :: Unpersist (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Unpersist (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Delta (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Delta (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Tee { inner } => { if persist_pulled_tees . contains (& (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >)) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } else { let inner_borrow = inner . borrow () ; if let HfPlusNode :: Persist (_) = inner_borrow . deref () { drop (inner_borrow) ; persist_pulled_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >) ; if let HfPlusNode :: Persist (box behind_persist) = inner . replace (HfPlusNode :: Placeholder) { * inner . borrow_mut () = behind_persist ; } else { unreachable ! () } * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } } } HfPlusNode :: Map { f : _ , input : deref!(HfPlusNode :: Persist (_)) , } => { if let HfPlusNode :: Map { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Map { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: FlatMap { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: FlatMap { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: FlatMap { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Filter { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Filter { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Filter { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Network { input : box HfPlusNode :: Persist (_) , .. } => { if let HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Union (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Union (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Union (left , right))) ; } else { unreachable ! () } } HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: CrossProduct (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,) ,)))) ; } else { unreachable ! () } } HfPlusNode :: Join (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Join (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: Join (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,))))) ; } else { unreachable ! () } } _ => { } } } pub fn persist_pullup (ir : Vec < HfPlusLeaf >) -> Vec < HfPlusLeaf > { let mut seen_tees = Default :: default () ; let mut persist_pulled_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| n , s | persist_pullup_node (n , s , & mut persist_pulled_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn persist_pullup_through_map () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } # [test] fn persist_pullup_behind_tee () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; let before_tee = flow . source_iter (& process , q ! (0 .. 10)) . tick_batch () . persist () ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } } } pub mod profiler { pub use std :: cell :: RefCell ; pub use hydroflow :: futures :: channel :: mpsc :: UnboundedSender ; pub use stageleft :: * ; pub use crate as hydroflow_plus ; pub use crate :: ir :: * ; pub use crate :: RuntimeContext ; pub fn increment_counter (count : & mut u64) { * count += 1 ; } pub fn quoted_any_fn < 'a , F : Fn (& usize) + 'a , Q : IntoQuotedMut < 'a , F > > (q : Q) -> Q { q } # [doc = " Add a profiling node before each node to count the cardinality of its input"] pub fn add_profiling_node < 'a > (node : & mut HfPlusNode < 'a > , _context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > , id : & mut u32 , seen_tees : & mut SeenTees < 'a > ,) { let my_id = * id ; * id += 1 ; node . transform_children (| node , seen_tees | { add_profiling_node (node , _context , counters , counter_queue , id , seen_tees) } , seen_tees ,) ; let orig_node = std :: mem :: replace (node , HfPlusNode :: Placeholder) ; * node = HfPlusNode :: Inspect { f : quoted_any_fn (q ! ({ counter_queue . borrow () . unbounded_send ((my_id as usize , counters . borrow () [my_id as usize])) . unwrap () ; counters . borrow_mut () [my_id as usize] = 0 ; move | _ | { hydroflow_plus :: profiler :: increment_counter (& mut counters . borrow_mut () [my_id as usize] ,) ; } })) . splice () . into () , input : Box :: new (orig_node) , } } # [doc = " Count the cardinality of each input and periodically output to a file"] pub fn profiling < 'a > (ir : Vec < HfPlusLeaf < 'a > > , context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > ,) -> Vec < HfPlusLeaf < 'a > > { let mut id = 0 ; let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | { add_profiling_node (node , context , counters , counter_queue , & mut id , seen_tees) } , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn profiler_wrapping_all_operators () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let runtime_context = flow . runtime_context () ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (& built . ir ()) ; let counters = RuntimeData :: new ("Fake") ; let counter_queue = RuntimeData :: new ("Fake") ; let pushed_down = built . with_default_optimize () . optimize_with (| ir | super :: profiling (ir , runtime_context , counters , counter_queue)) ; insta :: assert_debug_snapshot ! (& pushed_down . ir ()) ; let _ = pushed_down . compile_no_network :: < MultiGraph > () ; } } } pub mod properties { pub use std :: collections :: HashSet ; pub use stageleft :: * ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , SeenTees } ; pub use crate :: properties :: PropertyDatabase ; # [doc = " Allows us to convert the hydroflow datatype for folds to a binary operation for the algebra"] # [doc = " property tests."] # [allow (dead_code)] pub fn convert_hf_to_binary < I , A : Default , F : Fn (& mut A , I) > (f : F) -> impl Fn (I , I) -> A { move | a , b | { let mut acc = Default :: default () ; f (& mut acc , a) ; f (& mut acc , b) ; acc } } # [cfg (stageleft_macro)] impl PropertyDatabase { # [doc = " Tags the expression as commutative."] pub fn add_commutative_tag < 'a , I , A , F : Fn (& mut A , I) , Q : Quoted < 'a , F > + Clone > (& mut self , expr : Q ,) -> Q { let expr_clone = expr . clone () ; self . commutative . insert (expr_clone . splice ()) ; expr } pub fn is_tagged_commutative (& self , expr : & syn :: Expr) -> bool { self . commutative . contains (expr) } } pub fn properties_optimize_node < 'a > (node : & mut HfPlusNode < 'a > , db : & PropertyDatabase , seen_tees : & mut SeenTees < 'a > ,) { node . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , seen_tees ,) ; match node { HfPlusNode :: ReduceKeyed { f , .. } if db . is_tagged_commutative (& f . 0) => { dbg ! ("IDENTIFIED COMMUTATIVE OPTIMIZATION for {:?}" , & f) ; } _ => { } } } pub fn properties_optimize < 'a > (ir : Vec < HfPlusLeaf < 'a > > , db : & PropertyDatabase ,) -> Vec < HfPlusLeaf < 'a > > { let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use super :: * ; use crate :: deploy :: SingleProcessGraph ; use crate :: FlowBuilder ; # [test] fn test_property_database () { let mut db = PropertyDatabase :: default () ; assert ! (! db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; let _ = db . add_commutative_tag (q ! (| a : & mut i32 , b : i32 | * a += b)) ; assert ! (db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; } # [test] fn test_property_optimized () { let flow = FlowBuilder :: new () ; let mut database = PropertyDatabase :: default () ; let process = flow . process :: < () > () ; let counter_func = q ! (| count : & mut i32 , _ | * count += 1) ; let _ = database . add_commutative_tag (counter_func) ; flow . source_iter (& process , q ! (vec ! [])) . map (q ! (| string : String | (string , ()))) . tick_batch () . fold_keyed (q ! (|| 0) , counter_func) . all_ticks () . for_each (q ! (| (string , count) | println ! ("{}: {}" , string , count))) ; let built = flow . finalize () . optimize_with (| ir | properties_optimize (ir , & database)) . with_default_optimize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let _ = built . compile_no_network :: < SingleProcessGraph > () ; } } } pub use crate :: RuntimeContext ; # [cfg (stageleft_macro)] impl Copy for RuntimeContext < '_ > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Context > for RuntimeContext < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (quote ! (& context))) } } pub use crate :: HfCompiled ; # [cfg (stageleft_macro)] impl < 'a , ID > HfCompiled < 'a , ID > { pub fn hydroflow_ir (& self) -> & BTreeMap < usize , HydroflowGraph > { & self . hydroflow_ir } } # [cfg (stageleft_macro)] impl < 'a > HfCompiled < 'a , usize > { pub fn with_dynamic_id (self , id : impl Quoted < 'a , usize >) -> HfBuiltWithId < 'a > { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; let mut conditioned_tokens = None ; for (subgraph_id , flat_graph) in self . hydroflow_ir { let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; let my_extra_stmts = self . extra_stmts . get (& subgraph_id) . cloned () . unwrap_or_default () ; if let Some (conditioned_tokens) = conditioned_tokens . as_mut () { * conditioned_tokens = syn :: parse_quote ! { # conditioned_tokens else if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } } ; } else { conditioned_tokens = Some (syn :: parse_quote ! { if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } }) ; } } let conditioned_tokens : TokenStream = conditioned_tokens . unwrap () ; let id = id . splice () ; HfBuiltWithId { tokens : syn :: parse_quote ! ({ let __given_id = # id ; # conditioned_tokens else { panic ! ("Invalid node id: {}" , __given_id) ; } }) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfCompiled < 'a , () > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfCompiled < 'a , () > { fn to_tokens (mut self) -> (Option < TokenStream > , Option < TokenStream >) { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; if self . hydroflow_ir . len () != 1 { panic ! ("Expected exactly one subgraph in the Hydroflow IR") ; } let flat_graph = self . hydroflow_ir . remove (& 0) . unwrap () ; let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; (None , Some (tokens)) } } pub use crate :: HfBuiltWithId ; # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfBuiltWithId < 'a > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfBuiltWithId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (self . tokens)) } }
[INFO] [stdout]   |
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] error: `box` patterns have been removed (feature `box_patterns`)
[INFO] [stdout]  --> /opt/rustwide/target/debug/build/hydroflow_plus/5672655b657d1e44/out/lib_pub.rs:1:93106
[INFO] [stdout]   |
[INFO] [stdout] 1 | ...:: Persist (_) , } => { if let HfPlusNode :: Map { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: repl...
[INFO] [stdout]   |                                                                   ^^^
[INFO] [stdout]   |
[INFO] [stdout]   = help: enable feature `deref_patterns` instead and...
[INFO] [stdout] help: ...if possible just remove keyword `box`...
[INFO] [stdout]   |
[INFO] [stdout] 1 - pub use std :: collections :: BTreeMap ; pub use std :: marker :: PhantomData ; pub use hydroflow :: scheduled :: context :: Context ; pub use hydroflow :: scheduled :: graph :: Hydroflow ; pub use hydroflow :: * ; pub use lang :: graph :: { partition_graph , HydroflowGraph } ; pub use proc_macro2 :: TokenStream ; pub use quote :: quote ; pub use stageleft :: runtime_support :: FreeVariable ; pub use stageleft :: Quoted ; pub mod runtime_support { pub use bincode ; } pub mod stream { pub use std :: cell :: RefCell ; pub use std :: hash :: Hash ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow :: bytes :: Bytes ; pub use hydroflow :: futures :: Sink ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: quote ; pub use serde :: de :: DeserializeOwned ; pub use serde :: Serialize ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use syn :: parse_quote ; pub use crate :: builder :: { ClusterIds , FlowLeaves } ; pub use crate :: cycle :: { CycleCollection , CycleComplete } ; pub use crate :: ir :: { DebugInstantiate , HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { CanSend , Location , LocationId } ; pub use crate :: { Cluster , Optional , Singleton } ; pub use crate :: stream :: Unbounded ; pub use crate :: stream :: Bounded ; pub use crate :: stream :: NoTick ; pub use crate :: stream :: Tick ; pub use crate :: stream :: Stream ; # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Stream { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Stream < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Stream { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , C , N > > ,) -> Stream < 'a , (T , O) , W , C , N > where O : Clone , { let other : Optional < 'a , O , Bounded , C , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn cross_product < O > (self , other : Stream < 'a , O , W , C , N >) -> Stream < 'a , (T , O) , W , C , N > where T : Clone , O : Clone , { if self . location_kind != other . location_kind { panic ! ("cross_product must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossProduct (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn union (self , other : Stream < 'a , T , W , C , N >) -> Stream < 'a , T , W , C , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn dest_sink < S : Unpin + Sink < T > + 'a > (self , sink : impl Quoted < 'a , S >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: DestSink { sink : sink . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn first (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } # [doc = " Allow this stream through if the other stream has elements, otherwise the output is empty."] pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } # [doc = " Allow this stream through if the other stream is empty, otherwise the output is empty."] pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn enumerate (self) -> Stream < 'a , (usize , T) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Enumerate (Box :: new (self . ir_node . into_inner ())) ,) } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn sort (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Ord , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Sort (Box :: new (self . ir_node . into_inner ())) ,) } pub fn count (self) -> Singleton < 'a , usize , Bounded , Tick , N > { self . fold (q ! (|| 0usize) , q ! (| count , _ | * count += 1)) } pub fn delta (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } pub fn unique (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Eq + Hash , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unique (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn tick_batch (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_prefix (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { self . tick_batch () . persist () } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn for_each < F : Fn (T) + 'a > (self , f : impl IntoQuotedMut < 'a , F >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: ForEach { input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , f : f . splice () . into () , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Unbounded , NoTick , N > { pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . tick_batch () . continue_if (samples . first ()) . all_ticks () } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Unbounded , NoTick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , C , N : Location > Stream < 'a , T , Bounded , C , N > { pub fn filter_not_in (self , other : Stream < 'a , T , Bounded , C , N >) -> Stream < 'a , T , Bounded , C , N > where T : Eq + Hash , { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Difference (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Stream < 'a , & T , W , C , N > { pub fn cloned (self) -> Stream < 'a , T , W , C , N > { self . map (q ! (| d | d . clone ())) } } # [cfg (stageleft_macro)] impl < 'a , K , V1 , W , C , N : Location > Stream < 'a , (K , V1) , W , C , N > { pub fn join < W2 , V2 > (self , n : Stream < 'a , (K , V2) , W2 , C , N > ,) -> Stream < 'a , (K , (V1 , V2)) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Join (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } pub fn anti_join < W2 > (self , n : Stream < 'a , K , W2 , C , N >) -> Stream < 'a , (K , V1) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("anti_join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: AntiJoin (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , K : Eq + Hash , V , N : Location > Stream < 'a , (K , V) , Bounded , Tick , N > { pub fn fold_keyed < A , I : Fn () -> A + 'a , F : Fn (& mut A , V) + 'a > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , A) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FoldKeyed { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce_keyed < F : Fn (& mut V , V) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , V) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: ReduceKeyed { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } pub fn get_this_crate () -> TokenStream { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , Span :: call_site ()) ; quote ! { # ident } } } } pub fn serialize_bincode < T : Serialize > (is_demux : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if is_demux { parse_quote ! { map (| (id , data) | { (id , # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into ()) }) } } else { parse_quote ! { map (| data | { # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into () }) } } } pub fn deserialize_bincode < T : DeserializeOwned > (tagged : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if tagged { parse_quote ! { map (| res | { let (id , b) = res . unwrap () ; (id , # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& b) . unwrap ()) }) } } else { parse_quote ! { map (| res | { # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& res . unwrap ()) . unwrap () }) } } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn send_bincode < N2 : Location , CoreType > (self , other : & N2 ,) -> Stream < 'a , N :: Out < CoreType > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T > , CoreType : Serialize + DeserializeOwned , { let serialize_pipeline = Some (serialize_bincode :: < CoreType > (N :: is_demux ())) ; let deserialize_pipeline = Some (deserialize_bincode :: < CoreType > (N :: is_tagged ())) ; Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bytes < N2 : Location > (self , other : & N2 ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T > , { Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline : None , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline : if N :: is_tagged () { Some (parse_quote ! (map (| (id , b) | (id , b . unwrap () . freeze ())))) } else { Some (parse_quote ! (map (| b | b . unwrap () . freeze ()))) } , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bincode_interleaved < N2 : Location , Tag , CoreType > (self , other : & N2 ,) -> Stream < 'a , CoreType , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T , Out < CoreType > = (Tag , CoreType) > , CoreType : Serialize + DeserializeOwned , { self . send_bincode :: < N2 , CoreType > (other) . map (q ! (| (_ , b) | b)) } pub fn send_bytes_interleaved < N2 : Location , Tag > (self , other : & N2 ,) -> Stream < 'a , Bytes , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T , Out < Bytes > = (Tag , Bytes) > , { self . send_bytes :: < N2 > (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bincode < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < T > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) > , T : Clone + Serialize + DeserializeOwned , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bincode (other) } pub fn broadcast_bincode_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , T , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) , Out < T > = (Tag , T) > + 'a , T : Clone + Serialize + DeserializeOwned , { self . broadcast_bincode (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bytes < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) > + 'a , T : Clone , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bytes (other) } pub fn broadcast_bytes_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , Bytes , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) , Out < Bytes > = (Tag , Bytes) > + 'a , T : Clone , { self . broadcast_bytes (other) . map (q ! (| (_ , b) | b)) } } } pub use stream :: { Bounded , NoTick , Stream , Tick , Unbounded } ; pub mod singleton { pub use std :: cell :: RefCell ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use crate :: builder :: FlowLeaves ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial , CycleComplete } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: Stream ; pub use crate :: singleton :: CrossResult ; # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Singleton < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Singleton :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } pub use crate :: singleton :: Singleton ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Singleton { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleComplete < 'a > for Singleton < 'a , T , Bounded , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleCollectionWithInitial < 'a > for Singleton < 'a , T , Bounded , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , initial : Self , l : LocationId ,) -> Self { Singleton :: new (l , ir_leaves , HfPlusNode :: Union (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , }) , initial . ir_node . into_inner () . into () ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Singleton < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Singleton { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , U , W , C , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (Self :: other_ir_node (other)) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Singleton < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CrossSingleton (Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , Box :: new (HfPlusNode :: Unpersist (Box :: new (Self :: other_ir_node (other)))) ,))) ,) } } pub use crate :: singleton :: Optional ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Optional { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } pub fn some (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: new (singleton . location_kind , singleton . ir_leaves , singleton . ir_node . into_inner () ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > From < Singleton < 'a , T , W , C , N > > for Optional < 'a , T , W , C , N > { fn from (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: some (singleton) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Optional < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Optional { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn into_stream (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , Tick , N > > ,) -> Optional < 'a , (T , O) , Bounded , Tick , N > where O : Clone , { let other : Optional < 'a , O , Bounded , Tick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn union (self , other : Optional < 'a , T , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Optional < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_samples (self) -> Stream < 'a , T , Unbounded , NoTick , N > { self . latest_tick () . all_ticks () } pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . latest_tick () . continue_if (samples . first ()) . latest () . tick_samples () } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Unbounded , NoTick , N > > ,) -> Optional < 'a , (T , O) , Unbounded , NoTick , N > where O : Clone , { let other : Optional < 'a , O , Unbounded , NoTick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } self . latest_tick () . cross_singleton (other . latest_tick ()) . latest () } } } pub use singleton :: { Optional , Singleton } ; pub mod location { pub use std :: marker :: PhantomData ; pub use crate :: location :: LocationId ; pub use crate :: location :: Location ; pub use crate :: location :: Process ; # [cfg (stageleft_macro)] impl < P > Clone for Process < P > { fn clone (& self) -> Self { Process { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < P > Location for Process < P > { fn id (& self) -> LocationId { LocationId :: Process (self . id) } } pub use crate :: location :: Cluster ; # [cfg (stageleft_macro)] impl < C > Clone for Cluster < C > { fn clone (& self) -> Self { Cluster { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < C > Location for Cluster < C > { fn id (& self) -> LocationId { LocationId :: Cluster (self . id) } } pub use crate :: location :: CanSend ; # [cfg (stageleft_macro)] impl < P1 , P2 > CanSend < Process < P2 > > for Process < P1 > { type In < T > = T ; type Out < T > = T ; fn is_demux () -> bool { false } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < P1 , C2 > CanSend < Cluster < C2 > > for Process < P1 > { type In < T > = (u32 , T) ; type Out < T > = T ; fn is_demux () -> bool { true } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < C1 , P2 > CanSend < Process < P2 > > for Cluster < C1 > { type In < T > = T ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { false } fn is_tagged () -> bool { true } } # [cfg (stageleft_macro)] impl < C1 , C2 > CanSend < Cluster < C2 > > for Cluster < C1 > { type In < T > = (u32 , T) ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { true } fn is_tagged () -> bool { true } } } pub use location :: { Cluster , Process } ; pub mod deploy { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use stageleft :: Quoted ; pub mod graphs { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use super :: { LocalDeploy , Node , ProcessSpec } ; pub use crate :: deploy :: graphs :: SingleProcessGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for SingleProcessGraph { type Process = SingleNode ; type Cluster = SingleNode ; type Meta = () ; type GraphId = () ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { SingleNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { SingleNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , SingleProcessGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> SingleNode { SingleNode { } } } pub use crate :: deploy :: graphs :: SingleNode ; # [cfg (stageleft_macro)] impl Node for SingleNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } pub use crate :: deploy :: graphs :: MultiGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for MultiGraph { type Process = MultiNode ; type Cluster = MultiNode ; type Meta = () ; type GraphId = usize ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { MultiNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { MultiNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , MultiGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> MultiNode { MultiNode { } } } pub use crate :: deploy :: graphs :: MultiNode ; # [cfg (stageleft_macro)] impl Node for MultiNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } } pub use graphs :: * ; pub use crate :: deploy :: LocalDeploy ; pub use crate :: deploy :: Deploy ; # [cfg (stageleft_macro)] impl < 'a , T : Deploy < 'a , Process = N , Cluster = C , Meta = M , GraphId = R > , N : Node < Meta = M > , C : Node < Meta = M > , M : Default , R , > LocalDeploy < 'a > for T { type Process = N ; type Cluster = C ; type Meta = M ; type GraphId = R ; fn has_trivial_node () -> bool { < T as Deploy < 'a > > :: has_trivial_node () } fn trivial_process (id : usize) -> Self :: Process { < T as Deploy < 'a > > :: trivial_process (id) } fn trivial_cluster (id : usize) -> Self :: Cluster { < T as Deploy < 'a > > :: trivail_cluster (id) } } pub use crate :: deploy :: ProcessSpec ; pub use crate :: deploy :: ClusterSpec ; pub use crate :: deploy :: Node ; } pub use deploy :: { ClusterSpec , Deploy , ProcessSpec } ; pub mod cycle { pub use std :: marker :: PhantomData ; pub use crate :: builder :: FlowLeaves ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: cycle :: CycleComplete ; pub use crate :: cycle :: CycleCollection ; pub use crate :: cycle :: CycleCollectionWithInitial ; pub use crate :: cycle :: HfCycle ; # [cfg (stageleft_macro)] impl < 'a , S : CycleComplete < 'a > > HfCycle < 'a , S > { pub fn complete (self , stream : S) { let ident = self . ident ; S :: complete (stream , ident) } } } pub use cycle :: HfCycle ; pub mod builder { pub use std :: cell :: RefCell ; pub use std :: collections :: HashMap ; pub use std :: marker :: PhantomData ; pub use std :: rc :: Rc ; pub use std :: time :: Duration ; pub use hydroflow :: futures :: stream :: Stream as FuturesStream ; pub use hydroflow :: { tokio , tokio_stream } ; pub use internal :: TokenStream ; pub use proc_macro2 :: Span ; pub use quote :: quote ; pub use runtime_support :: FreeVariable ; pub use stageleft :: * ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Cluster , Location , LocationId , Process } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: { HfCycle , Optional , RuntimeContext , Singleton , Stream } ; pub mod built { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use hydroflow_lang :: graph :: { eliminate_extra_unions_tees , HydroflowGraph } ; pub use super :: deploy :: { DeployFlow , DeployResult } ; pub use crate :: deploy :: { ClusterSpec , Deploy , LocalDeploy , ProcessSpec } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Cluster , Process } ; pub use crate :: HfCompiled ; pub use crate :: builder :: built :: BuiltFlow ; # [cfg (stageleft_macro)] impl < 'a > Drop for BuiltFlow < 'a > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped BuiltFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn ir (& self) -> & Vec < HfPlusLeaf < 'a > > { & self . ir } pub fn optimize_with (mut self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> BuiltFlow < 'a > { self . used = true ; BuiltFlow { ir : f (std :: mem :: take (& mut self . ir)) , processes : std :: mem :: take (& mut self . processes) , clusters : std :: mem :: take (& mut self . clusters) , used : false , _phantom : PhantomData , } } } pub fn build_inner (ir : & mut Vec < HfPlusLeaf >) -> BTreeMap < usize , HydroflowGraph > { let mut builders = BTreeMap :: new () ; let mut built_tees = HashMap :: new () ; let mut next_stmt_id = 0 ; for leaf in ir { leaf . emit (& mut builders , & mut built_tees , & mut next_stmt_id) ; } builders . into_iter () . map (| (k , v) | { let (mut flat_graph , _ , _) = v . build () ; eliminate_extra_unions_tees (& mut flat_graph) ; (k , flat_graph) }) . collect () } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn compile_no_network < D : LocalDeploy < 'a > > (mut self) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; HfCompiled { hydroflow_ir : build_inner (& mut self . ir) , extra_stmts : BTreeMap :: new () , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> BuiltFlow < 'a > { self . optimize_with (crate :: persist_pullup :: persist_pullup) } fn into_deploy < D : LocalDeploy < 'a > > (mut self) -> DeployFlow < 'a , D > { self . used = true ; let processes = if D :: has_trivial_node () { self . processes . iter () . map (| id | (* id , D :: trivial_process (* id))) . collect () } else { HashMap :: new () } ; let clusters = if D :: has_trivial_node () { self . clusters . iter () . map (| id | (* id , D :: trivial_cluster (* id))) . collect () } else { HashMap :: new () } ; DeployFlow { ir : std :: mem :: take (& mut self . ir) , nodes : processes , clusters , used : false , _phantom : PhantomData , } } pub fn with_process < P , D : LocalDeploy < 'a > > (self , process : & Process < P > , spec : impl ProcessSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_process (process , spec) } pub fn with_cluster < C , D : LocalDeploy < 'a > > (self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_cluster (cluster , spec) } pub fn compile < D : Deploy < 'a > + 'a > (self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . into_deploy :: < D > () . compile (env) } pub fn deploy < D : Deploy < 'a , CompileEnv = () > + 'a > (self , env : & mut D :: InstantiateEnv ,) -> DeployResult < 'a , D > { self . into_deploy :: < D > () . deploy (env) } } } pub mod deploy { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use proc_macro2 :: Span ; pub use stageleft :: Quoted ; pub use super :: built :: build_inner ; pub use crate :: deploy :: { LocalDeploy , Node } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: { Cluster , ClusterSpec , Deploy , HfCompiled , Process , ProcessSpec } ; pub use crate :: builder :: deploy :: DeployFlow ; # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > Drop for DeployFlow < 'a , D > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped DeployFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > DeployFlow < 'a , D > { pub fn with_process < P > (mut self , process : & Process < P > , spec : impl ProcessSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < P > () . to_string () ; self . nodes . insert (process . id , spec . build (process . id , & tag_name)) ; self } pub fn with_cluster < C > (mut self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < C > () . to_string () ; self . clusters . insert (cluster . id , spec . build (cluster . id , & tag_name)) ; self } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployFlow < 'a , D > { pub fn compile (mut self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; let mut seen_tees : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | leaf . compile_network :: < D > (env , & mut seen_tees , & self . nodes , & self . clusters)) . collect () ; let extra_stmts = self . extra_stmts (env) ; HfCompiled { hydroflow_ir : build_inner (& mut ir_leaves_networked) , extra_stmts , _phantom : PhantomData , } } fn extra_stmts (& self , env : & < D as Deploy < 'a > > :: CompileEnv) -> BTreeMap < usize , Vec < syn :: Stmt > > { let all_locations_count = self . nodes . len () + self . clusters . len () ; let mut extra_stmts : BTreeMap < usize , Vec < syn :: Stmt > > = BTreeMap :: new () ; for & c_id in self . clusters . keys () { let self_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , c_id) , Span :: call_site () ,) ; let self_id_expr = D :: cluster_self_id (env) . splice () ; extra_stmts . entry (c_id) . or_default () . push (syn :: parse_quote ! { let # self_id_ident = # self_id_expr ; }) ; for other_location in 0 .. all_locations_count { let other_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , c_id) , Span :: call_site () ,) ; let other_id_expr = D :: cluster_ids (env , c_id) . splice () ; extra_stmts . entry (other_location) . or_default () . push (syn :: parse_quote ! { let # other_id_ident = # other_id_expr ; }) ; } } extra_stmts } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a , CompileEnv = () > > DeployFlow < 'a , D > { # [must_use] pub fn deploy (mut self , env : & mut D :: InstantiateEnv) -> DeployResult < 'a , D > { self . used = true ; let mut seen_tees_instantiate : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | { leaf . compile_network :: < D > (& () , & mut seen_tees_instantiate , & self . nodes , & self . clusters ,) }) . collect () ; let mut compiled = build_inner (& mut ir_leaves_networked) ; let mut extra_stmts = self . extra_stmts (& ()) ; let mut meta = D :: Meta :: default () ; let (mut processes , mut clusters) = (std :: mem :: take (& mut self . nodes) . into_iter () . map (| (node_id , node) | { node . instantiate (env , & mut meta , compiled . remove (& node_id) . unwrap () , extra_stmts . remove (& node_id) . unwrap_or_default () ,) ; (node_id , node) }) . collect :: < HashMap < _ , _ > > () , std :: mem :: take (& mut self . clusters) . into_iter () . map (| (cluster_id , cluster) | { cluster . instantiate (env , & mut meta , compiled . remove (& cluster_id) . unwrap () , extra_stmts . remove (& cluster_id) . unwrap_or_default () ,) ; (cluster_id , cluster) }) . collect :: < HashMap < _ , _ > > () ,) ; for node in processes . values_mut () { node . update_meta (& meta) ; } for cluster in clusters . values_mut () { cluster . update_meta (& meta) ; } let mut seen_tees_connect = HashMap :: new () ; for leaf in ir_leaves_networked { leaf . connect_network (& mut seen_tees_connect) ; } DeployResult { processes , clusters , } } } pub use crate :: builder :: deploy :: DeployResult ; # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployResult < 'a , D > { pub fn get_process < P > (& self , p : & Process < P >) -> & D :: Process { let id = match p . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . processes . get (& id) . unwrap () } pub fn get_cluster < C > (& self , c : & Cluster < C >) -> & D :: Cluster { let id = match c . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . clusters . get (& id) . unwrap () } } } # [doc = " Tracks the leaves of the dataflow IR. This is referenced by"] # [doc = " `Stream` and `HfCycle` to build the IR. The inner option will"] # [doc = " be set to `None` when this builder is finalized."] pub type FlowLeaves < 'a > = Rc < RefCell < Option < Vec < HfPlusLeaf < 'a > > > > > ; pub use crate :: builder :: ClusterIds ; # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Vec < u32 > > for ClusterIds < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , & 'a Vec < u32 > > for ClusterIds < 'a > { } # [derive (Copy , Clone)] pub struct ClusterSelfId < 'a > { pub id : usize , pub _phantom : PhantomData < & 'a mut & 'a u32 > , } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < u32 > for ClusterSelfId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , u32 > for ClusterSelfId < 'a > { } pub use crate :: builder :: FlowBuilder ; # [cfg (stageleft_macro)] impl < 'a > Drop for FlowBuilder < 'a > { fn drop (& mut self) { if ! self . finalized { panic ! ("Dropped FlowBuilder without finalizing, you may have forgotten to call `with_default_optimize`, `optimize_with`, or `finalize`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > QuotedContext for FlowBuilder < 'a > { fn create () -> Self { FlowBuilder :: new () } } # [cfg (stageleft_macro)] impl < 'a > FlowBuilder < 'a > { # [allow (clippy :: new_without_default)] pub fn new () -> FlowBuilder < 'a > { FlowBuilder { ir_leaves : Rc :: new (RefCell :: new (Some (Vec :: new ()))) , nodes : RefCell :: new (vec ! []) , clusters : RefCell :: new (vec ! []) , cycle_ids : RefCell :: new (HashMap :: new ()) , next_node_id : RefCell :: new (0) , finalized : false , _phantom : PhantomData , } } pub fn finalize (mut self) -> built :: BuiltFlow < 'a > { self . finalized = true ; built :: BuiltFlow { ir : self . ir_leaves . borrow_mut () . take () . unwrap () , processes : self . nodes . replace (vec ! []) , clusters : self . clusters . replace (vec ! []) , used : false , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> built :: BuiltFlow < 'a > { self . finalize () . with_default_optimize () } pub fn optimize_with (self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> built :: BuiltFlow < 'a > { self . finalize () . optimize_with (f) } pub fn ir_leaves (& self) -> & FlowLeaves < 'a > { & self . ir_leaves } pub fn process < P > (& self) -> Process < P > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . nodes . borrow_mut () . push (id) ; Process { id , _phantom : PhantomData , } } pub fn cluster < C > (& self) -> Cluster < C > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . clusters . borrow_mut () . push (id) ; Cluster { id , _phantom : PhantomData , } } pub fn runtime_context (& self) -> RuntimeContext < 'a > { RuntimeContext { _phantom : PhantomData , } } pub fn cluster_members < C > (& self , cluster : & Cluster < C > ,) -> impl Quoted < 'a , & 'a Vec < u32 > > + Copy + 'a { ClusterIds { id : cluster . id , _phantom : PhantomData , } } pub fn cluster_self_id < C > (& self , cluster : & Cluster < C >) -> impl Quoted < 'a , u32 > + Copy + 'a { ClusterSelfId { id : cluster . id , _phantom : PhantomData , } } pub fn spin < L : Location > (& self , on : & L) -> Stream < 'a , () , Unbounded , NoTick , L > { Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Spin () , location_kind : on . id () , })) ,) } pub fn spin_batch < L : Location > (& self , on : & L , batch_size : impl Quoted < 'a , usize > + Copy + 'a ,) -> Stream < 'a , () , Bounded , Tick , L > { self . spin (on) . flat_map (q ! (move | _ | 0 .. batch_size)) . map (q ! (| _ | ())) . tick_batch () } pub fn source_stream < T , E : FuturesStream < Item = T > + Unpin , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Unbounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Stream (e . into ()) , location_kind : on . id () , })) ,) } pub fn source_iter < T , E : IntoIterator < Item = T > , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Bounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , })) ,) } pub fn singleton < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Singleton < 'a , T , Bounded , NoTick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Singleton :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,)))) ,) } pub fn singleton_first_tick < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Optional < 'a , T , Bounded , Tick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,) } pub fn source_interval < L : Location > (& self , on : & L , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , () , Unbounded , NoTick , L > { let interval = interval . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : on . id () , })) ,) } pub fn source_interval_delayed < L : Location > (& self , on : & L , delay : impl Quoted < 'a , Duration > + Copy + 'a , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , tokio :: time :: Instant , Unbounded , NoTick , L > { self . source_stream (on , q ! (tokio_stream :: wrappers :: IntervalStream :: new (tokio :: time :: interval_at (tokio :: time :: Instant :: now () + delay , interval))) ,) . tick_batch () . first () . latest () } pub fn cycle < S : CycleCollection < 'a > > (& self , on : & S :: Location) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , on . id ()) ,) } pub fn cycle_with_initial < S : CycleCollectionWithInitial < 'a > > (& self , on : & S :: Location , initial : S ,) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , initial , on . id ()) ,) } } } pub use builder :: FlowBuilder ; pub mod ir { pub use core :: panic ; pub use std :: cell :: RefCell ; pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow_lang :: graph :: FlatGraphBuilder ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: ToTokens ; pub use syn :: parse_quote ; pub use crate :: deploy :: Deploy ; pub use crate :: location :: LocationId ; pub use crate :: ir :: DebugExpr ; # [cfg (stageleft_macro)] impl From < syn :: Expr > for DebugExpr { fn from (expr : syn :: Expr) -> DebugExpr { DebugExpr (expr) } } # [cfg (stageleft_macro)] impl Deref for DebugExpr { type Target = syn :: Expr ; fn deref (& self) -> & Self :: Target { & self . 0 } } # [cfg (stageleft_macro)] impl ToTokens for DebugExpr { fn to_tokens (& self , tokens : & mut TokenStream) { self . 0 . to_tokens (tokens) ; } } # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugExpr { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "{}" , self . 0 . to_token_stream ()) } } pub use crate :: ir :: DebugInstantiate ; # [cfg (stageleft_macro)] impl < 'a > std :: fmt :: Debug for DebugInstantiate < 'a > { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<network instantiate>") } } pub use crate :: ir :: DebugPipelineFn ; # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugPipelineFn { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<function>") } } pub use crate :: ir :: HfPlusSource ; pub use crate :: ir :: HfPlusLeaf ; # [cfg (stageleft_macro)] impl < 'a > HfPlusLeaf < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . compile_network :: < D > (compile_env , s , nodes , clusters) ; } , seen_tees ,) } pub fn connect_network (self , seen_tees : & mut SeenTees < 'a >) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . connect_network (s) ; } , seen_tees ,) } pub fn transform_children (self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) -> HfPlusLeaf < 'a > { match self { HfPlusLeaf :: ForEach { f , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: ForEach { f , input } } HfPlusLeaf :: DestSink { sink , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: DestSink { sink , input } } HfPlusLeaf :: CycleSink { ident , location_kind , mut input , } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: CycleSink { ident , location_kind , input , } } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) { match self { HfPlusLeaf :: ForEach { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> for_each (# f) ; }) ; } HfPlusLeaf :: DestSink { sink , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink) ; }) ; } HfPlusLeaf :: CycleSink { ident , location_kind , input , } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; assert_eq ! (input_location_id , * location_id , "cycle_sink location mismatch") ; graph_builders . entry (* location_id) . or_default () . add_statement (parse_quote ! { # ident = # input_ident ; }) ; } } } } pub use crate :: ir :: HfPlusNode ; pub type SeenTees < 'a > = HashMap < * const RefCell < HfPlusNode < 'a > > , Rc < RefCell < HfPlusNode < 'a > > > > ; # [cfg (stageleft_macro)] impl < 'a > HfPlusNode < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (& mut self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) { self . transform_children (| n , s | n . compile_network :: < D > (compile_env , s , nodes , clusters) , seen_tees ,) ; if let HfPlusNode :: Network { from_location , to_location , instantiate_fn , .. } = self { let (sink_expr , source_expr , connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { let ((sink , source) , connect_fn) = match (from_location , to_location) { (LocationId :: Process (from) , LocationId :: Process (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: o2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Process (from) , LocationId :: Cluster (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: o2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Process (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: m2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Cluster (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: m2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } } ; (sink , source , connect_fn) } DebugInstantiate :: Finalized (_ , _ , _) => panic ! ("network already finalized") , } ; * instantiate_fn = DebugInstantiate :: Finalized (sink_expr , source_expr , connect_fn) ; } } pub fn connect_network (& mut self , seen_tees : & mut SeenTees < 'a >) { self . transform_children (| n , s | n . connect_network (s) , seen_tees) ; if let HfPlusNode :: Network { instantiate_fn , .. } = self { match instantiate_fn { DebugInstantiate :: Building () => panic ! ("network not built") , DebugInstantiate :: Finalized (_ , _ , ref connect_fn) => { connect_fn () ; } } } } pub fn transform_children (& mut self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) { match self { HfPlusNode :: Placeholder => { panic ! () ; } HfPlusNode :: Source { .. } => { } HfPlusNode :: CycleSource { .. } => { } HfPlusNode :: Tee { inner } => { if let Some (transformed) = seen_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { * inner = transformed . clone () ; } else { let transformed_cell = Rc :: new (RefCell :: new (HfPlusNode :: Placeholder)) ; seen_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , transformed_cell . clone () ,) ; let mut orig = inner . replace (HfPlusNode :: Placeholder) ; transform (& mut orig , seen_tees) ; * transformed_cell . borrow_mut () = orig ; * inner = transformed_cell ; } } HfPlusNode :: Persist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Unpersist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Delta (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Union (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossProduct (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossSingleton (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Join (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Difference (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: AntiJoin (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Map { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FlatMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Filter { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FilterMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Sort (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: DeferTick (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Enumerate (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Inspect { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Unique (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Fold { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FoldKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Reduce { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: ReduceKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Network { input , .. } => { transform (input . as_mut () , seen_tees) ; } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) -> (syn :: Ident , usize) { match self { HfPlusNode :: Placeholder => { panic ! () } HfPlusNode :: Persist (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let persist_id = * next_stmt_id ; * next_stmt_id += 1 ; let persist_ident = syn :: Ident :: new (& format ! ("stream_{}" , persist_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # persist_ident = # inner_ident -> persist ::<'static > () ; }) ; (persist_ident , location) } HfPlusNode :: Unpersist (_) => { panic ! ("Unpersist is a marker node and should have been optimized away. This is likely a compiler bug.") } HfPlusNode :: Delta (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let delta_id = * next_stmt_id ; * next_stmt_id += 1 ; let delta_ident = syn :: Ident :: new (& format ! ("stream_{}" , delta_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # delta_ident = # inner_ident -> multiset_delta () ; }) ; (delta_ident , location) } HfPlusNode :: Source { source , location_kind , } => { let source_id = * next_stmt_id ; * next_stmt_id += 1 ; let source_ident = syn :: Ident :: new (& format ! ("stream_{}" , source_id) , Span :: call_site ()) ; let source_stmt = match source { HfPlusSource :: Stream (expr) => { parse_quote ! { # source_ident = source_stream (# expr) ; } } HfPlusSource :: Iter (expr) => { parse_quote ! { # source_ident = source_iter (# expr) ; } } HfPlusSource :: Interval (expr) => { parse_quote ! { # source_ident = source_interval (# expr) ; } } HfPlusSource :: Spin () => { parse_quote ! { # source_ident = spin () ; } } } ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; graph_builders . entry (* location_id) . or_default () . add_statement (source_stmt) ; (source_ident , * location_id) } HfPlusNode :: CycleSource { ident , location_kind , } => { let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; (ident . clone () , * location_id) } HfPlusNode :: Tee { inner } => { if let Some (ret) = built_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { ret . clone () } else { let (inner_ident , inner_location_id) = inner . borrow () . emit (graph_builders , built_tees , next_stmt_id) ; let tee_id = * next_stmt_id ; * next_stmt_id += 1 ; let tee_ident = syn :: Ident :: new (& format ! ("stream_{}" , tee_id) , Span :: call_site ()) ; let builder = graph_builders . entry (inner_location_id) . or_default () ; builder . add_statement (parse_quote ! { # tee_ident = # inner_ident -> tee () ; }) ; built_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , (tee_ident . clone () , inner_location_id) ,) ; (tee_ident , inner_location_id) } } HfPlusNode :: Union (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "union inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let union_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # union_ident = union () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [0] # union_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # union_ident ; }) ; (union_ident , left_location_id) } HfPlusNode :: CrossSingleton (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "cross_singleton inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let cross_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # cross_ident = cross_singleton () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [input] # cross_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [single] # cross_ident ; }) ; (cross_ident , left_location_id) } HfPlusNode :: CrossProduct (..) | HfPlusNode :: Join (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: CrossProduct (..)) { parse_quote ! (cross_join_multiset) } else { parse_quote ! (join_multiset) } ; let (HfPlusNode :: CrossProduct (left , right) | HfPlusNode :: Join (left , right)) = self else { unreachable ! () } ; let (left_inner , left_was_persist) = if let HfPlusNode :: Persist (left) = left . as_ref () { (left , true) } else { (left , false) } ; let (right_inner , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left_inner . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right_inner . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "join / cross product inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; match (left_was_persist , right_was_persist) { (true , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'static > () ; }) ; } (true , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'tick > () ; }) ; } (false , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } (false , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } } ; builder . add_statement (parse_quote ! { # left_ident -> [0] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Difference (..) | HfPlusNode :: AntiJoin (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Difference (..)) { parse_quote ! (difference_multiset) } else { parse_quote ! (anti_join_multiset) } ; let (HfPlusNode :: Difference (left , right) | HfPlusNode :: AntiJoin (left , right)) = self else { unreachable ! () } ; let (right , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "difference / anti join inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; if right_was_persist { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } else { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } builder . add_statement (parse_quote ! { # left_ident -> [pos] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [neg] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Map { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let map_id = * next_stmt_id ; * next_stmt_id += 1 ; let map_ident = syn :: Ident :: new (& format ! ("stream_{}" , map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # map_ident = # input_ident -> map (# f) ; }) ; (map_ident , input_location_id) } HfPlusNode :: FlatMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let flat_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let flat_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , flat_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # flat_map_ident = # input_ident -> flat_map (# f) ; }) ; (flat_map_ident , input_location_id) } HfPlusNode :: Filter { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_ident = # input_ident -> filter (# f) ; }) ; (filter_ident , input_location_id) } HfPlusNode :: FilterMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_map_ident = # input_ident -> filter_map (# f) ; }) ; (filter_map_ident , input_location_id) } HfPlusNode :: Sort (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sort_id = * next_stmt_id ; * next_stmt_id += 1 ; let sort_ident = syn :: Ident :: new (& format ! ("stream_{}" , sort_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # sort_ident = # input_ident -> sort () ; }) ; (sort_ident , input_location_id) } HfPlusNode :: DeferTick (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let defer_tick_id = * next_stmt_id ; * next_stmt_id += 1 ; let defer_tick_ident = syn :: Ident :: new (& format ! ("stream_{}" , defer_tick_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # defer_tick_ident = # input_ident -> defer_tick_lazy () ; }) ; (defer_tick_ident , input_location_id) } HfPlusNode :: Enumerate (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let enumerate_id = * next_stmt_id ; * next_stmt_id += 1 ; let enumerate_ident = syn :: Ident :: new (& format ! ("stream_{}" , enumerate_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # enumerate_ident = # input_ident -> enumerate () ; }) ; (enumerate_ident , input_location_id) } HfPlusNode :: Inspect { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let inspect_id = * next_stmt_id ; * next_stmt_id += 1 ; let inspect_ident = syn :: Ident :: new (& format ! ("stream_{}" , inspect_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # inspect_ident = # input_ident -> inspect (# f) ; }) ; (inspect_ident , input_location_id) } HfPlusNode :: Unique (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let unique_id = * next_stmt_id ; * next_stmt_id += 1 ; let unique_ident = syn :: Ident :: new (& format ! ("stream_{}" , unique_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # unique_ident = # input_ident -> unique ::<'tick > () ; }) ; (unique_ident , input_location_id) } HfPlusNode :: Fold { .. } | HfPlusNode :: FoldKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Fold { .. }) { parse_quote ! (fold) } else { parse_quote ! (fold_keyed) } ; let (HfPlusNode :: Fold { init , acc , input } | HfPlusNode :: FoldKeyed { init , acc , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let fold_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'static > (# init , # acc) ; }) ; } else { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'tick > (# init , # acc) ; }) ; } (fold_ident , input_location_id) } HfPlusNode :: Reduce { .. } | HfPlusNode :: ReduceKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Reduce { .. }) { parse_quote ! (reduce) } else { parse_quote ! (reduce_keyed) } ; let (HfPlusNode :: Reduce { f , input } | HfPlusNode :: ReduceKeyed { f , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let reduce_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'static > (# f) ; }) ; } else { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'tick > (# f) ; }) ; } (reduce_ident , input_location_id) } HfPlusNode :: Network { from_location : _ , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input , } => { let (sink_expr , source_expr , _connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { panic ! ("Expected the network to be finalized") } DebugInstantiate :: Finalized (sink , source , connect_fn) => { (sink , source , connect_fn) } } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sender_builder = graph_builders . entry (input_location_id) . or_default () ; if let Some (serialize_pipeline) = serialize_pipeline { sender_builder . add_statement (parse_quote ! { # input_ident -> # serialize_pipeline -> dest_sink (# sink_expr) ; }) ; } else { sender_builder . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink_expr) ; }) ; } let to_id = match to_location { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let receiver_builder = graph_builders . entry (* to_id) . or_default () ; let receiver_stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let receiver_stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , receiver_stream_id) , Span :: call_site ()) ; if let Some (deserialize_pipeline) = deserialize_pipeline { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) -> # deserialize_pipeline ; }) ; } else { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) ; }) ; } (receiver_stream_ident , * to_id) } } } } } pub mod persist_pullup { pub use std :: cell :: RefCell ; pub use std :: collections :: HashSet ; pub use std :: ops :: Deref ; pub use crate :: ir :: * ; pub fn persist_pullup_node < 'a > (node : & mut HfPlusNode < 'a > , seen_tees : & mut SeenTees < 'a > , persist_pulled_tees : & mut HashSet < * const RefCell < HfPlusNode < 'a > > > ,) { node . transform_children (| n , s | persist_pullup_node (n , s , persist_pulled_tees) , seen_tees ,) ; match node { HfPlusNode :: Unpersist (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Unpersist (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Delta (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Delta (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Tee { inner } => { if persist_pulled_tees . contains (& (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >)) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } else { let inner_borrow = inner . borrow () ; if let HfPlusNode :: Persist (_) = inner_borrow . deref () { drop (inner_borrow) ; persist_pulled_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >) ; if let HfPlusNode :: Persist (box behind_persist) = inner . replace (HfPlusNode :: Placeholder) { * inner . borrow_mut () = behind_persist ; } else { unreachable ! () } * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } } } HfPlusNode :: Map { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Map { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Map { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: FlatMap { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: FlatMap { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: FlatMap { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Filter { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Filter { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Filter { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Network { input : box HfPlusNode :: Persist (_) , .. } => { if let HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Union (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Union (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Union (left , right))) ; } else { unreachable ! () } } HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: CrossProduct (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,) ,)))) ; } else { unreachable ! () } } HfPlusNode :: Join (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Join (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: Join (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,))))) ; } else { unreachable ! () } } _ => { } } } pub fn persist_pullup (ir : Vec < HfPlusLeaf >) -> Vec < HfPlusLeaf > { let mut seen_tees = Default :: default () ; let mut persist_pulled_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| n , s | persist_pullup_node (n , s , & mut persist_pulled_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn persist_pullup_through_map () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } # [test] fn persist_pullup_behind_tee () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; let before_tee = flow . source_iter (& process , q ! (0 .. 10)) . tick_batch () . persist () ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } } } pub mod profiler { pub use std :: cell :: RefCell ; pub use hydroflow :: futures :: channel :: mpsc :: UnboundedSender ; pub use stageleft :: * ; pub use crate as hydroflow_plus ; pub use crate :: ir :: * ; pub use crate :: RuntimeContext ; pub fn increment_counter (count : & mut u64) { * count += 1 ; } pub fn quoted_any_fn < 'a , F : Fn (& usize) + 'a , Q : IntoQuotedMut < 'a , F > > (q : Q) -> Q { q } # [doc = " Add a profiling node before each node to count the cardinality of its input"] pub fn add_profiling_node < 'a > (node : & mut HfPlusNode < 'a > , _context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > , id : & mut u32 , seen_tees : & mut SeenTees < 'a > ,) { let my_id = * id ; * id += 1 ; node . transform_children (| node , seen_tees | { add_profiling_node (node , _context , counters , counter_queue , id , seen_tees) } , seen_tees ,) ; let orig_node = std :: mem :: replace (node , HfPlusNode :: Placeholder) ; * node = HfPlusNode :: Inspect { f : quoted_any_fn (q ! ({ counter_queue . borrow () . unbounded_send ((my_id as usize , counters . borrow () [my_id as usize])) . unwrap () ; counters . borrow_mut () [my_id as usize] = 0 ; move | _ | { hydroflow_plus :: profiler :: increment_counter (& mut counters . borrow_mut () [my_id as usize] ,) ; } })) . splice () . into () , input : Box :: new (orig_node) , } } # [doc = " Count the cardinality of each input and periodically output to a file"] pub fn profiling < 'a > (ir : Vec < HfPlusLeaf < 'a > > , context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > ,) -> Vec < HfPlusLeaf < 'a > > { let mut id = 0 ; let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | { add_profiling_node (node , context , counters , counter_queue , & mut id , seen_tees) } , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn profiler_wrapping_all_operators () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let runtime_context = flow . runtime_context () ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (& built . ir ()) ; let counters = RuntimeData :: new ("Fake") ; let counter_queue = RuntimeData :: new ("Fake") ; let pushed_down = built . with_default_optimize () . optimize_with (| ir | super :: profiling (ir , runtime_context , counters , counter_queue)) ; insta :: assert_debug_snapshot ! (& pushed_down . ir ()) ; let _ = pushed_down . compile_no_network :: < MultiGraph > () ; } } } pub mod properties { pub use std :: collections :: HashSet ; pub use stageleft :: * ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , SeenTees } ; pub use crate :: properties :: PropertyDatabase ; # [doc = " Allows us to convert the hydroflow datatype for folds to a binary operation for the algebra"] # [doc = " property tests."] # [allow (dead_code)] pub fn convert_hf_to_binary < I , A : Default , F : Fn (& mut A , I) > (f : F) -> impl Fn (I , I) -> A { move | a , b | { let mut acc = Default :: default () ; f (& mut acc , a) ; f (& mut acc , b) ; acc } } # [cfg (stageleft_macro)] impl PropertyDatabase { # [doc = " Tags the expression as commutative."] pub fn add_commutative_tag < 'a , I , A , F : Fn (& mut A , I) , Q : Quoted < 'a , F > + Clone > (& mut self , expr : Q ,) -> Q { let expr_clone = expr . clone () ; self . commutative . insert (expr_clone . splice ()) ; expr } pub fn is_tagged_commutative (& self , expr : & syn :: Expr) -> bool { self . commutative . contains (expr) } } pub fn properties_optimize_node < 'a > (node : & mut HfPlusNode < 'a > , db : & PropertyDatabase , seen_tees : & mut SeenTees < 'a > ,) { node . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , seen_tees ,) ; match node { HfPlusNode :: ReduceKeyed { f , .. } if db . is_tagged_commutative (& f . 0) => { dbg ! ("IDENTIFIED COMMUTATIVE OPTIMIZATION for {:?}" , & f) ; } _ => { } } } pub fn properties_optimize < 'a > (ir : Vec < HfPlusLeaf < 'a > > , db : & PropertyDatabase ,) -> Vec < HfPlusLeaf < 'a > > { let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use super :: * ; use crate :: deploy :: SingleProcessGraph ; use crate :: FlowBuilder ; # [test] fn test_property_database () { let mut db = PropertyDatabase :: default () ; assert ! (! db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; let _ = db . add_commutative_tag (q ! (| a : & mut i32 , b : i32 | * a += b)) ; assert ! (db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; } # [test] fn test_property_optimized () { let flow = FlowBuilder :: new () ; let mut database = PropertyDatabase :: default () ; let process = flow . process :: < () > () ; let counter_func = q ! (| count : & mut i32 , _ | * count += 1) ; let _ = database . add_commutative_tag (counter_func) ; flow . source_iter (& process , q ! (vec ! [])) . map (q ! (| string : String | (string , ()))) . tick_batch () . fold_keyed (q ! (|| 0) , counter_func) . all_ticks () . for_each (q ! (| (string , count) | println ! ("{}: {}" , string , count))) ; let built = flow . finalize () . optimize_with (| ir | properties_optimize (ir , & database)) . with_default_optimize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let _ = built . compile_no_network :: < SingleProcessGraph > () ; } } } pub use crate :: RuntimeContext ; # [cfg (stageleft_macro)] impl Copy for RuntimeContext < '_ > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Context > for RuntimeContext < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (quote ! (& context))) } } pub use crate :: HfCompiled ; # [cfg (stageleft_macro)] impl < 'a , ID > HfCompiled < 'a , ID > { pub fn hydroflow_ir (& self) -> & BTreeMap < usize , HydroflowGraph > { & self . hydroflow_ir } } # [cfg (stageleft_macro)] impl < 'a > HfCompiled < 'a , usize > { pub fn with_dynamic_id (self , id : impl Quoted < 'a , usize >) -> HfBuiltWithId < 'a > { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; let mut conditioned_tokens = None ; for (subgraph_id , flat_graph) in self . hydroflow_ir { let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; let my_extra_stmts = self . extra_stmts . get (& subgraph_id) . cloned () . unwrap_or_default () ; if let Some (conditioned_tokens) = conditioned_tokens . as_mut () { * conditioned_tokens = syn :: parse_quote ! { # conditioned_tokens else if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } } ; } else { conditioned_tokens = Some (syn :: parse_quote ! { if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } }) ; } } let conditioned_tokens : TokenStream = conditioned_tokens . unwrap () ; let id = id . splice () ; HfBuiltWithId { tokens : syn :: parse_quote ! ({ let __given_id = # id ; # conditioned_tokens else { panic ! ("Invalid node id: {}" , __given_id) ; } }) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfCompiled < 'a , () > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfCompiled < 'a , () > { fn to_tokens (mut self) -> (Option < TokenStream > , Option < TokenStream >) { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; if self . hydroflow_ir . len () != 1 { panic ! ("Expected exactly one subgraph in the Hydroflow IR") ; } let flat_graph = self . hydroflow_ir . remove (& 0) . unwrap () ; let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; (None , Some (tokens)) } } pub use crate :: HfBuiltWithId ; # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfBuiltWithId < 'a > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfBuiltWithId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (self . tokens)) } }
[INFO] [stdout] 1 + pub use std :: collections :: BTreeMap ; pub use std :: marker :: PhantomData ; pub use hydroflow :: scheduled :: context :: Context ; pub use hydroflow :: scheduled :: graph :: Hydroflow ; pub use hydroflow :: * ; pub use lang :: graph :: { partition_graph , HydroflowGraph } ; pub use proc_macro2 :: TokenStream ; pub use quote :: quote ; pub use stageleft :: runtime_support :: FreeVariable ; pub use stageleft :: Quoted ; pub mod runtime_support { pub use bincode ; } pub mod stream { pub use std :: cell :: RefCell ; pub use std :: hash :: Hash ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow :: bytes :: Bytes ; pub use hydroflow :: futures :: Sink ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: quote ; pub use serde :: de :: DeserializeOwned ; pub use serde :: Serialize ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use syn :: parse_quote ; pub use crate :: builder :: { ClusterIds , FlowLeaves } ; pub use crate :: cycle :: { CycleCollection , CycleComplete } ; pub use crate :: ir :: { DebugInstantiate , HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { CanSend , Location , LocationId } ; pub use crate :: { Cluster , Optional , Singleton } ; pub use crate :: stream :: Unbounded ; pub use crate :: stream :: Bounded ; pub use crate :: stream :: NoTick ; pub use crate :: stream :: Tick ; pub use crate :: stream :: Stream ; # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Stream { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Stream < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Stream { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , C , N > > ,) -> Stream < 'a , (T , O) , W , C , N > where O : Clone , { let other : Optional < 'a , O , Bounded , C , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn cross_product < O > (self , other : Stream < 'a , O , W , C , N >) -> Stream < 'a , (T , O) , W , C , N > where T : Clone , O : Clone , { if self . location_kind != other . location_kind { panic ! ("cross_product must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossProduct (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn union (self , other : Stream < 'a , T , W , C , N >) -> Stream < 'a , T , W , C , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn dest_sink < S : Unpin + Sink < T > + 'a > (self , sink : impl Quoted < 'a , S >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: DestSink { sink : sink . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn first (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } # [doc = " Allow this stream through if the other stream has elements, otherwise the output is empty."] pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } # [doc = " Allow this stream through if the other stream is empty, otherwise the output is empty."] pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn enumerate (self) -> Stream < 'a , (usize , T) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Enumerate (Box :: new (self . ir_node . into_inner ())) ,) } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn sort (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Ord , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Sort (Box :: new (self . ir_node . into_inner ())) ,) } pub fn count (self) -> Singleton < 'a , usize , Bounded , Tick , N > { self . fold (q ! (|| 0usize) , q ! (| count , _ | * count += 1)) } pub fn delta (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } pub fn unique (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Eq + Hash , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unique (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn tick_batch (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_prefix (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { self . tick_batch () . persist () } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn for_each < F : Fn (T) + 'a > (self , f : impl IntoQuotedMut < 'a , F >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: ForEach { input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , f : f . splice () . into () , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Unbounded , NoTick , N > { pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . tick_batch () . continue_if (samples . first ()) . all_ticks () } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Unbounded , NoTick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , C , N : Location > Stream < 'a , T , Bounded , C , N > { pub fn filter_not_in (self , other : Stream < 'a , T , Bounded , C , N >) -> Stream < 'a , T , Bounded , C , N > where T : Eq + Hash , { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Difference (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Stream < 'a , & T , W , C , N > { pub fn cloned (self) -> Stream < 'a , T , W , C , N > { self . map (q ! (| d | d . clone ())) } } # [cfg (stageleft_macro)] impl < 'a , K , V1 , W , C , N : Location > Stream < 'a , (K , V1) , W , C , N > { pub fn join < W2 , V2 > (self , n : Stream < 'a , (K , V2) , W2 , C , N > ,) -> Stream < 'a , (K , (V1 , V2)) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Join (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } pub fn anti_join < W2 > (self , n : Stream < 'a , K , W2 , C , N >) -> Stream < 'a , (K , V1) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("anti_join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: AntiJoin (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , K : Eq + Hash , V , N : Location > Stream < 'a , (K , V) , Bounded , Tick , N > { pub fn fold_keyed < A , I : Fn () -> A + 'a , F : Fn (& mut A , V) + 'a > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , A) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FoldKeyed { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce_keyed < F : Fn (& mut V , V) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , V) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: ReduceKeyed { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } pub fn get_this_crate () -> TokenStream { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , Span :: call_site ()) ; quote ! { # ident } } } } pub fn serialize_bincode < T : Serialize > (is_demux : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if is_demux { parse_quote ! { map (| (id , data) | { (id , # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into ()) }) } } else { parse_quote ! { map (| data | { # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into () }) } } } pub fn deserialize_bincode < T : DeserializeOwned > (tagged : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if tagged { parse_quote ! { map (| res | { let (id , b) = res . unwrap () ; (id , # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& b) . unwrap ()) }) } } else { parse_quote ! { map (| res | { # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& res . unwrap ()) . unwrap () }) } } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn send_bincode < N2 : Location , CoreType > (self , other : & N2 ,) -> Stream < 'a , N :: Out < CoreType > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T > , CoreType : Serialize + DeserializeOwned , { let serialize_pipeline = Some (serialize_bincode :: < CoreType > (N :: is_demux ())) ; let deserialize_pipeline = Some (deserialize_bincode :: < CoreType > (N :: is_tagged ())) ; Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bytes < N2 : Location > (self , other : & N2 ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T > , { Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline : None , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline : if N :: is_tagged () { Some (parse_quote ! (map (| (id , b) | (id , b . unwrap () . freeze ())))) } else { Some (parse_quote ! (map (| b | b . unwrap () . freeze ()))) } , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bincode_interleaved < N2 : Location , Tag , CoreType > (self , other : & N2 ,) -> Stream < 'a , CoreType , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T , Out < CoreType > = (Tag , CoreType) > , CoreType : Serialize + DeserializeOwned , { self . send_bincode :: < N2 , CoreType > (other) . map (q ! (| (_ , b) | b)) } pub fn send_bytes_interleaved < N2 : Location , Tag > (self , other : & N2 ,) -> Stream < 'a , Bytes , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T , Out < Bytes > = (Tag , Bytes) > , { self . send_bytes :: < N2 > (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bincode < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < T > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) > , T : Clone + Serialize + DeserializeOwned , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bincode (other) } pub fn broadcast_bincode_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , T , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) , Out < T > = (Tag , T) > + 'a , T : Clone + Serialize + DeserializeOwned , { self . broadcast_bincode (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bytes < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) > + 'a , T : Clone , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bytes (other) } pub fn broadcast_bytes_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , Bytes , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) , Out < Bytes > = (Tag , Bytes) > + 'a , T : Clone , { self . broadcast_bytes (other) . map (q ! (| (_ , b) | b)) } } } pub use stream :: { Bounded , NoTick , Stream , Tick , Unbounded } ; pub mod singleton { pub use std :: cell :: RefCell ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use crate :: builder :: FlowLeaves ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial , CycleComplete } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: Stream ; pub use crate :: singleton :: CrossResult ; # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Singleton < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Singleton :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } pub use crate :: singleton :: Singleton ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Singleton { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleComplete < 'a > for Singleton < 'a , T , Bounded , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleCollectionWithInitial < 'a > for Singleton < 'a , T , Bounded , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , initial : Self , l : LocationId ,) -> Self { Singleton :: new (l , ir_leaves , HfPlusNode :: Union (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , }) , initial . ir_node . into_inner () . into () ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Singleton < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Singleton { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , U , W , C , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (Self :: other_ir_node (other)) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Singleton < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CrossSingleton (Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , Box :: new (HfPlusNode :: Unpersist (Box :: new (Self :: other_ir_node (other)))) ,))) ,) } } pub use crate :: singleton :: Optional ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Optional { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } pub fn some (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: new (singleton . location_kind , singleton . ir_leaves , singleton . ir_node . into_inner () ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > From < Singleton < 'a , T , W , C , N > > for Optional < 'a , T , W , C , N > { fn from (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: some (singleton) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Optional < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Optional { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn into_stream (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , Tick , N > > ,) -> Optional < 'a , (T , O) , Bounded , Tick , N > where O : Clone , { let other : Optional < 'a , O , Bounded , Tick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn union (self , other : Optional < 'a , T , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Optional < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_samples (self) -> Stream < 'a , T , Unbounded , NoTick , N > { self . latest_tick () . all_ticks () } pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . latest_tick () . continue_if (samples . first ()) . latest () . tick_samples () } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Unbounded , NoTick , N > > ,) -> Optional < 'a , (T , O) , Unbounded , NoTick , N > where O : Clone , { let other : Optional < 'a , O , Unbounded , NoTick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } self . latest_tick () . cross_singleton (other . latest_tick ()) . latest () } } } pub use singleton :: { Optional , Singleton } ; pub mod location { pub use std :: marker :: PhantomData ; pub use crate :: location :: LocationId ; pub use crate :: location :: Location ; pub use crate :: location :: Process ; # [cfg (stageleft_macro)] impl < P > Clone for Process < P > { fn clone (& self) -> Self { Process { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < P > Location for Process < P > { fn id (& self) -> LocationId { LocationId :: Process (self . id) } } pub use crate :: location :: Cluster ; # [cfg (stageleft_macro)] impl < C > Clone for Cluster < C > { fn clone (& self) -> Self { Cluster { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < C > Location for Cluster < C > { fn id (& self) -> LocationId { LocationId :: Cluster (self . id) } } pub use crate :: location :: CanSend ; # [cfg (stageleft_macro)] impl < P1 , P2 > CanSend < Process < P2 > > for Process < P1 > { type In < T > = T ; type Out < T > = T ; fn is_demux () -> bool { false } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < P1 , C2 > CanSend < Cluster < C2 > > for Process < P1 > { type In < T > = (u32 , T) ; type Out < T > = T ; fn is_demux () -> bool { true } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < C1 , P2 > CanSend < Process < P2 > > for Cluster < C1 > { type In < T > = T ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { false } fn is_tagged () -> bool { true } } # [cfg (stageleft_macro)] impl < C1 , C2 > CanSend < Cluster < C2 > > for Cluster < C1 > { type In < T > = (u32 , T) ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { true } fn is_tagged () -> bool { true } } } pub use location :: { Cluster , Process } ; pub mod deploy { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use stageleft :: Quoted ; pub mod graphs { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use super :: { LocalDeploy , Node , ProcessSpec } ; pub use crate :: deploy :: graphs :: SingleProcessGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for SingleProcessGraph { type Process = SingleNode ; type Cluster = SingleNode ; type Meta = () ; type GraphId = () ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { SingleNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { SingleNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , SingleProcessGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> SingleNode { SingleNode { } } } pub use crate :: deploy :: graphs :: SingleNode ; # [cfg (stageleft_macro)] impl Node for SingleNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } pub use crate :: deploy :: graphs :: MultiGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for MultiGraph { type Process = MultiNode ; type Cluster = MultiNode ; type Meta = () ; type GraphId = usize ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { MultiNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { MultiNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , MultiGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> MultiNode { MultiNode { } } } pub use crate :: deploy :: graphs :: MultiNode ; # [cfg (stageleft_macro)] impl Node for MultiNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } } pub use graphs :: * ; pub use crate :: deploy :: LocalDeploy ; pub use crate :: deploy :: Deploy ; # [cfg (stageleft_macro)] impl < 'a , T : Deploy < 'a , Process = N , Cluster = C , Meta = M , GraphId = R > , N : Node < Meta = M > , C : Node < Meta = M > , M : Default , R , > LocalDeploy < 'a > for T { type Process = N ; type Cluster = C ; type Meta = M ; type GraphId = R ; fn has_trivial_node () -> bool { < T as Deploy < 'a > > :: has_trivial_node () } fn trivial_process (id : usize) -> Self :: Process { < T as Deploy < 'a > > :: trivial_process (id) } fn trivial_cluster (id : usize) -> Self :: Cluster { < T as Deploy < 'a > > :: trivail_cluster (id) } } pub use crate :: deploy :: ProcessSpec ; pub use crate :: deploy :: ClusterSpec ; pub use crate :: deploy :: Node ; } pub use deploy :: { ClusterSpec , Deploy , ProcessSpec } ; pub mod cycle { pub use std :: marker :: PhantomData ; pub use crate :: builder :: FlowLeaves ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: cycle :: CycleComplete ; pub use crate :: cycle :: CycleCollection ; pub use crate :: cycle :: CycleCollectionWithInitial ; pub use crate :: cycle :: HfCycle ; # [cfg (stageleft_macro)] impl < 'a , S : CycleComplete < 'a > > HfCycle < 'a , S > { pub fn complete (self , stream : S) { let ident = self . ident ; S :: complete (stream , ident) } } } pub use cycle :: HfCycle ; pub mod builder { pub use std :: cell :: RefCell ; pub use std :: collections :: HashMap ; pub use std :: marker :: PhantomData ; pub use std :: rc :: Rc ; pub use std :: time :: Duration ; pub use hydroflow :: futures :: stream :: Stream as FuturesStream ; pub use hydroflow :: { tokio , tokio_stream } ; pub use internal :: TokenStream ; pub use proc_macro2 :: Span ; pub use quote :: quote ; pub use runtime_support :: FreeVariable ; pub use stageleft :: * ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Cluster , Location , LocationId , Process } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: { HfCycle , Optional , RuntimeContext , Singleton , Stream } ; pub mod built { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use hydroflow_lang :: graph :: { eliminate_extra_unions_tees , HydroflowGraph } ; pub use super :: deploy :: { DeployFlow , DeployResult } ; pub use crate :: deploy :: { ClusterSpec , Deploy , LocalDeploy , ProcessSpec } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Cluster , Process } ; pub use crate :: HfCompiled ; pub use crate :: builder :: built :: BuiltFlow ; # [cfg (stageleft_macro)] impl < 'a > Drop for BuiltFlow < 'a > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped BuiltFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn ir (& self) -> & Vec < HfPlusLeaf < 'a > > { & self . ir } pub fn optimize_with (mut self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> BuiltFlow < 'a > { self . used = true ; BuiltFlow { ir : f (std :: mem :: take (& mut self . ir)) , processes : std :: mem :: take (& mut self . processes) , clusters : std :: mem :: take (& mut self . clusters) , used : false , _phantom : PhantomData , } } } pub fn build_inner (ir : & mut Vec < HfPlusLeaf >) -> BTreeMap < usize , HydroflowGraph > { let mut builders = BTreeMap :: new () ; let mut built_tees = HashMap :: new () ; let mut next_stmt_id = 0 ; for leaf in ir { leaf . emit (& mut builders , & mut built_tees , & mut next_stmt_id) ; } builders . into_iter () . map (| (k , v) | { let (mut flat_graph , _ , _) = v . build () ; eliminate_extra_unions_tees (& mut flat_graph) ; (k , flat_graph) }) . collect () } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn compile_no_network < D : LocalDeploy < 'a > > (mut self) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; HfCompiled { hydroflow_ir : build_inner (& mut self . ir) , extra_stmts : BTreeMap :: new () , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> BuiltFlow < 'a > { self . optimize_with (crate :: persist_pullup :: persist_pullup) } fn into_deploy < D : LocalDeploy < 'a > > (mut self) -> DeployFlow < 'a , D > { self . used = true ; let processes = if D :: has_trivial_node () { self . processes . iter () . map (| id | (* id , D :: trivial_process (* id))) . collect () } else { HashMap :: new () } ; let clusters = if D :: has_trivial_node () { self . clusters . iter () . map (| id | (* id , D :: trivial_cluster (* id))) . collect () } else { HashMap :: new () } ; DeployFlow { ir : std :: mem :: take (& mut self . ir) , nodes : processes , clusters , used : false , _phantom : PhantomData , } } pub fn with_process < P , D : LocalDeploy < 'a > > (self , process : & Process < P > , spec : impl ProcessSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_process (process , spec) } pub fn with_cluster < C , D : LocalDeploy < 'a > > (self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_cluster (cluster , spec) } pub fn compile < D : Deploy < 'a > + 'a > (self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . into_deploy :: < D > () . compile (env) } pub fn deploy < D : Deploy < 'a , CompileEnv = () > + 'a > (self , env : & mut D :: InstantiateEnv ,) -> DeployResult < 'a , D > { self . into_deploy :: < D > () . deploy (env) } } } pub mod deploy { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use proc_macro2 :: Span ; pub use stageleft :: Quoted ; pub use super :: built :: build_inner ; pub use crate :: deploy :: { LocalDeploy , Node } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: { Cluster , ClusterSpec , Deploy , HfCompiled , Process , ProcessSpec } ; pub use crate :: builder :: deploy :: DeployFlow ; # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > Drop for DeployFlow < 'a , D > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped DeployFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > DeployFlow < 'a , D > { pub fn with_process < P > (mut self , process : & Process < P > , spec : impl ProcessSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < P > () . to_string () ; self . nodes . insert (process . id , spec . build (process . id , & tag_name)) ; self } pub fn with_cluster < C > (mut self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < C > () . to_string () ; self . clusters . insert (cluster . id , spec . build (cluster . id , & tag_name)) ; self } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployFlow < 'a , D > { pub fn compile (mut self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; let mut seen_tees : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | leaf . compile_network :: < D > (env , & mut seen_tees , & self . nodes , & self . clusters)) . collect () ; let extra_stmts = self . extra_stmts (env) ; HfCompiled { hydroflow_ir : build_inner (& mut ir_leaves_networked) , extra_stmts , _phantom : PhantomData , } } fn extra_stmts (& self , env : & < D as Deploy < 'a > > :: CompileEnv) -> BTreeMap < usize , Vec < syn :: Stmt > > { let all_locations_count = self . nodes . len () + self . clusters . len () ; let mut extra_stmts : BTreeMap < usize , Vec < syn :: Stmt > > = BTreeMap :: new () ; for & c_id in self . clusters . keys () { let self_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , c_id) , Span :: call_site () ,) ; let self_id_expr = D :: cluster_self_id (env) . splice () ; extra_stmts . entry (c_id) . or_default () . push (syn :: parse_quote ! { let # self_id_ident = # self_id_expr ; }) ; for other_location in 0 .. all_locations_count { let other_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , c_id) , Span :: call_site () ,) ; let other_id_expr = D :: cluster_ids (env , c_id) . splice () ; extra_stmts . entry (other_location) . or_default () . push (syn :: parse_quote ! { let # other_id_ident = # other_id_expr ; }) ; } } extra_stmts } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a , CompileEnv = () > > DeployFlow < 'a , D > { # [must_use] pub fn deploy (mut self , env : & mut D :: InstantiateEnv) -> DeployResult < 'a , D > { self . used = true ; let mut seen_tees_instantiate : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | { leaf . compile_network :: < D > (& () , & mut seen_tees_instantiate , & self . nodes , & self . clusters ,) }) . collect () ; let mut compiled = build_inner (& mut ir_leaves_networked) ; let mut extra_stmts = self . extra_stmts (& ()) ; let mut meta = D :: Meta :: default () ; let (mut processes , mut clusters) = (std :: mem :: take (& mut self . nodes) . into_iter () . map (| (node_id , node) | { node . instantiate (env , & mut meta , compiled . remove (& node_id) . unwrap () , extra_stmts . remove (& node_id) . unwrap_or_default () ,) ; (node_id , node) }) . collect :: < HashMap < _ , _ > > () , std :: mem :: take (& mut self . clusters) . into_iter () . map (| (cluster_id , cluster) | { cluster . instantiate (env , & mut meta , compiled . remove (& cluster_id) . unwrap () , extra_stmts . remove (& cluster_id) . unwrap_or_default () ,) ; (cluster_id , cluster) }) . collect :: < HashMap < _ , _ > > () ,) ; for node in processes . values_mut () { node . update_meta (& meta) ; } for cluster in clusters . values_mut () { cluster . update_meta (& meta) ; } let mut seen_tees_connect = HashMap :: new () ; for leaf in ir_leaves_networked { leaf . connect_network (& mut seen_tees_connect) ; } DeployResult { processes , clusters , } } } pub use crate :: builder :: deploy :: DeployResult ; # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployResult < 'a , D > { pub fn get_process < P > (& self , p : & Process < P >) -> & D :: Process { let id = match p . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . processes . get (& id) . unwrap () } pub fn get_cluster < C > (& self , c : & Cluster < C >) -> & D :: Cluster { let id = match c . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . clusters . get (& id) . unwrap () } } } # [doc = " Tracks the leaves of the dataflow IR. This is referenced by"] # [doc = " `Stream` and `HfCycle` to build the IR. The inner option will"] # [doc = " be set to `None` when this builder is finalized."] pub type FlowLeaves < 'a > = Rc < RefCell < Option < Vec < HfPlusLeaf < 'a > > > > > ; pub use crate :: builder :: ClusterIds ; # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Vec < u32 > > for ClusterIds < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , & 'a Vec < u32 > > for ClusterIds < 'a > { } # [derive (Copy , Clone)] pub struct ClusterSelfId < 'a > { pub id : usize , pub _phantom : PhantomData < & 'a mut & 'a u32 > , } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < u32 > for ClusterSelfId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , u32 > for ClusterSelfId < 'a > { } pub use crate :: builder :: FlowBuilder ; # [cfg (stageleft_macro)] impl < 'a > Drop for FlowBuilder < 'a > { fn drop (& mut self) { if ! self . finalized { panic ! ("Dropped FlowBuilder without finalizing, you may have forgotten to call `with_default_optimize`, `optimize_with`, or `finalize`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > QuotedContext for FlowBuilder < 'a > { fn create () -> Self { FlowBuilder :: new () } } # [cfg (stageleft_macro)] impl < 'a > FlowBuilder < 'a > { # [allow (clippy :: new_without_default)] pub fn new () -> FlowBuilder < 'a > { FlowBuilder { ir_leaves : Rc :: new (RefCell :: new (Some (Vec :: new ()))) , nodes : RefCell :: new (vec ! []) , clusters : RefCell :: new (vec ! []) , cycle_ids : RefCell :: new (HashMap :: new ()) , next_node_id : RefCell :: new (0) , finalized : false , _phantom : PhantomData , } } pub fn finalize (mut self) -> built :: BuiltFlow < 'a > { self . finalized = true ; built :: BuiltFlow { ir : self . ir_leaves . borrow_mut () . take () . unwrap () , processes : self . nodes . replace (vec ! []) , clusters : self . clusters . replace (vec ! []) , used : false , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> built :: BuiltFlow < 'a > { self . finalize () . with_default_optimize () } pub fn optimize_with (self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> built :: BuiltFlow < 'a > { self . finalize () . optimize_with (f) } pub fn ir_leaves (& self) -> & FlowLeaves < 'a > { & self . ir_leaves } pub fn process < P > (& self) -> Process < P > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . nodes . borrow_mut () . push (id) ; Process { id , _phantom : PhantomData , } } pub fn cluster < C > (& self) -> Cluster < C > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . clusters . borrow_mut () . push (id) ; Cluster { id , _phantom : PhantomData , } } pub fn runtime_context (& self) -> RuntimeContext < 'a > { RuntimeContext { _phantom : PhantomData , } } pub fn cluster_members < C > (& self , cluster : & Cluster < C > ,) -> impl Quoted < 'a , & 'a Vec < u32 > > + Copy + 'a { ClusterIds { id : cluster . id , _phantom : PhantomData , } } pub fn cluster_self_id < C > (& self , cluster : & Cluster < C >) -> impl Quoted < 'a , u32 > + Copy + 'a { ClusterSelfId { id : cluster . id , _phantom : PhantomData , } } pub fn spin < L : Location > (& self , on : & L) -> Stream < 'a , () , Unbounded , NoTick , L > { Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Spin () , location_kind : on . id () , })) ,) } pub fn spin_batch < L : Location > (& self , on : & L , batch_size : impl Quoted < 'a , usize > + Copy + 'a ,) -> Stream < 'a , () , Bounded , Tick , L > { self . spin (on) . flat_map (q ! (move | _ | 0 .. batch_size)) . map (q ! (| _ | ())) . tick_batch () } pub fn source_stream < T , E : FuturesStream < Item = T > + Unpin , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Unbounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Stream (e . into ()) , location_kind : on . id () , })) ,) } pub fn source_iter < T , E : IntoIterator < Item = T > , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Bounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , })) ,) } pub fn singleton < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Singleton < 'a , T , Bounded , NoTick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Singleton :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,)))) ,) } pub fn singleton_first_tick < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Optional < 'a , T , Bounded , Tick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,) } pub fn source_interval < L : Location > (& self , on : & L , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , () , Unbounded , NoTick , L > { let interval = interval . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : on . id () , })) ,) } pub fn source_interval_delayed < L : Location > (& self , on : & L , delay : impl Quoted < 'a , Duration > + Copy + 'a , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , tokio :: time :: Instant , Unbounded , NoTick , L > { self . source_stream (on , q ! (tokio_stream :: wrappers :: IntervalStream :: new (tokio :: time :: interval_at (tokio :: time :: Instant :: now () + delay , interval))) ,) . tick_batch () . first () . latest () } pub fn cycle < S : CycleCollection < 'a > > (& self , on : & S :: Location) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , on . id ()) ,) } pub fn cycle_with_initial < S : CycleCollectionWithInitial < 'a > > (& self , on : & S :: Location , initial : S ,) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , initial , on . id ()) ,) } } } pub use builder :: FlowBuilder ; pub mod ir { pub use core :: panic ; pub use std :: cell :: RefCell ; pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow_lang :: graph :: FlatGraphBuilder ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: ToTokens ; pub use syn :: parse_quote ; pub use crate :: deploy :: Deploy ; pub use crate :: location :: LocationId ; pub use crate :: ir :: DebugExpr ; # [cfg (stageleft_macro)] impl From < syn :: Expr > for DebugExpr { fn from (expr : syn :: Expr) -> DebugExpr { DebugExpr (expr) } } # [cfg (stageleft_macro)] impl Deref for DebugExpr { type Target = syn :: Expr ; fn deref (& self) -> & Self :: Target { & self . 0 } } # [cfg (stageleft_macro)] impl ToTokens for DebugExpr { fn to_tokens (& self , tokens : & mut TokenStream) { self . 0 . to_tokens (tokens) ; } } # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugExpr { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "{}" , self . 0 . to_token_stream ()) } } pub use crate :: ir :: DebugInstantiate ; # [cfg (stageleft_macro)] impl < 'a > std :: fmt :: Debug for DebugInstantiate < 'a > { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<network instantiate>") } } pub use crate :: ir :: DebugPipelineFn ; # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugPipelineFn { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<function>") } } pub use crate :: ir :: HfPlusSource ; pub use crate :: ir :: HfPlusLeaf ; # [cfg (stageleft_macro)] impl < 'a > HfPlusLeaf < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . compile_network :: < D > (compile_env , s , nodes , clusters) ; } , seen_tees ,) } pub fn connect_network (self , seen_tees : & mut SeenTees < 'a >) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . connect_network (s) ; } , seen_tees ,) } pub fn transform_children (self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) -> HfPlusLeaf < 'a > { match self { HfPlusLeaf :: ForEach { f , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: ForEach { f , input } } HfPlusLeaf :: DestSink { sink , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: DestSink { sink , input } } HfPlusLeaf :: CycleSink { ident , location_kind , mut input , } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: CycleSink { ident , location_kind , input , } } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) { match self { HfPlusLeaf :: ForEach { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> for_each (# f) ; }) ; } HfPlusLeaf :: DestSink { sink , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink) ; }) ; } HfPlusLeaf :: CycleSink { ident , location_kind , input , } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; assert_eq ! (input_location_id , * location_id , "cycle_sink location mismatch") ; graph_builders . entry (* location_id) . or_default () . add_statement (parse_quote ! { # ident = # input_ident ; }) ; } } } } pub use crate :: ir :: HfPlusNode ; pub type SeenTees < 'a > = HashMap < * const RefCell < HfPlusNode < 'a > > , Rc < RefCell < HfPlusNode < 'a > > > > ; # [cfg (stageleft_macro)] impl < 'a > HfPlusNode < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (& mut self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) { self . transform_children (| n , s | n . compile_network :: < D > (compile_env , s , nodes , clusters) , seen_tees ,) ; if let HfPlusNode :: Network { from_location , to_location , instantiate_fn , .. } = self { let (sink_expr , source_expr , connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { let ((sink , source) , connect_fn) = match (from_location , to_location) { (LocationId :: Process (from) , LocationId :: Process (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: o2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Process (from) , LocationId :: Cluster (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: o2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Process (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: m2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Cluster (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: m2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } } ; (sink , source , connect_fn) } DebugInstantiate :: Finalized (_ , _ , _) => panic ! ("network already finalized") , } ; * instantiate_fn = DebugInstantiate :: Finalized (sink_expr , source_expr , connect_fn) ; } } pub fn connect_network (& mut self , seen_tees : & mut SeenTees < 'a >) { self . transform_children (| n , s | n . connect_network (s) , seen_tees) ; if let HfPlusNode :: Network { instantiate_fn , .. } = self { match instantiate_fn { DebugInstantiate :: Building () => panic ! ("network not built") , DebugInstantiate :: Finalized (_ , _ , ref connect_fn) => { connect_fn () ; } } } } pub fn transform_children (& mut self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) { match self { HfPlusNode :: Placeholder => { panic ! () ; } HfPlusNode :: Source { .. } => { } HfPlusNode :: CycleSource { .. } => { } HfPlusNode :: Tee { inner } => { if let Some (transformed) = seen_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { * inner = transformed . clone () ; } else { let transformed_cell = Rc :: new (RefCell :: new (HfPlusNode :: Placeholder)) ; seen_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , transformed_cell . clone () ,) ; let mut orig = inner . replace (HfPlusNode :: Placeholder) ; transform (& mut orig , seen_tees) ; * transformed_cell . borrow_mut () = orig ; * inner = transformed_cell ; } } HfPlusNode :: Persist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Unpersist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Delta (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Union (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossProduct (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossSingleton (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Join (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Difference (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: AntiJoin (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Map { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FlatMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Filter { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FilterMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Sort (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: DeferTick (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Enumerate (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Inspect { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Unique (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Fold { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FoldKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Reduce { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: ReduceKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Network { input , .. } => { transform (input . as_mut () , seen_tees) ; } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) -> (syn :: Ident , usize) { match self { HfPlusNode :: Placeholder => { panic ! () } HfPlusNode :: Persist (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let persist_id = * next_stmt_id ; * next_stmt_id += 1 ; let persist_ident = syn :: Ident :: new (& format ! ("stream_{}" , persist_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # persist_ident = # inner_ident -> persist ::<'static > () ; }) ; (persist_ident , location) } HfPlusNode :: Unpersist (_) => { panic ! ("Unpersist is a marker node and should have been optimized away. This is likely a compiler bug.") } HfPlusNode :: Delta (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let delta_id = * next_stmt_id ; * next_stmt_id += 1 ; let delta_ident = syn :: Ident :: new (& format ! ("stream_{}" , delta_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # delta_ident = # inner_ident -> multiset_delta () ; }) ; (delta_ident , location) } HfPlusNode :: Source { source , location_kind , } => { let source_id = * next_stmt_id ; * next_stmt_id += 1 ; let source_ident = syn :: Ident :: new (& format ! ("stream_{}" , source_id) , Span :: call_site ()) ; let source_stmt = match source { HfPlusSource :: Stream (expr) => { parse_quote ! { # source_ident = source_stream (# expr) ; } } HfPlusSource :: Iter (expr) => { parse_quote ! { # source_ident = source_iter (# expr) ; } } HfPlusSource :: Interval (expr) => { parse_quote ! { # source_ident = source_interval (# expr) ; } } HfPlusSource :: Spin () => { parse_quote ! { # source_ident = spin () ; } } } ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; graph_builders . entry (* location_id) . or_default () . add_statement (source_stmt) ; (source_ident , * location_id) } HfPlusNode :: CycleSource { ident , location_kind , } => { let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; (ident . clone () , * location_id) } HfPlusNode :: Tee { inner } => { if let Some (ret) = built_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { ret . clone () } else { let (inner_ident , inner_location_id) = inner . borrow () . emit (graph_builders , built_tees , next_stmt_id) ; let tee_id = * next_stmt_id ; * next_stmt_id += 1 ; let tee_ident = syn :: Ident :: new (& format ! ("stream_{}" , tee_id) , Span :: call_site ()) ; let builder = graph_builders . entry (inner_location_id) . or_default () ; builder . add_statement (parse_quote ! { # tee_ident = # inner_ident -> tee () ; }) ; built_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , (tee_ident . clone () , inner_location_id) ,) ; (tee_ident , inner_location_id) } } HfPlusNode :: Union (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "union inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let union_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # union_ident = union () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [0] # union_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # union_ident ; }) ; (union_ident , left_location_id) } HfPlusNode :: CrossSingleton (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "cross_singleton inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let cross_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # cross_ident = cross_singleton () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [input] # cross_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [single] # cross_ident ; }) ; (cross_ident , left_location_id) } HfPlusNode :: CrossProduct (..) | HfPlusNode :: Join (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: CrossProduct (..)) { parse_quote ! (cross_join_multiset) } else { parse_quote ! (join_multiset) } ; let (HfPlusNode :: CrossProduct (left , right) | HfPlusNode :: Join (left , right)) = self else { unreachable ! () } ; let (left_inner , left_was_persist) = if let HfPlusNode :: Persist (left) = left . as_ref () { (left , true) } else { (left , false) } ; let (right_inner , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left_inner . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right_inner . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "join / cross product inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; match (left_was_persist , right_was_persist) { (true , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'static > () ; }) ; } (true , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'tick > () ; }) ; } (false , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } (false , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } } ; builder . add_statement (parse_quote ! { # left_ident -> [0] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Difference (..) | HfPlusNode :: AntiJoin (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Difference (..)) { parse_quote ! (difference_multiset) } else { parse_quote ! (anti_join_multiset) } ; let (HfPlusNode :: Difference (left , right) | HfPlusNode :: AntiJoin (left , right)) = self else { unreachable ! () } ; let (right , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "difference / anti join inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; if right_was_persist { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } else { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } builder . add_statement (parse_quote ! { # left_ident -> [pos] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [neg] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Map { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let map_id = * next_stmt_id ; * next_stmt_id += 1 ; let map_ident = syn :: Ident :: new (& format ! ("stream_{}" , map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # map_ident = # input_ident -> map (# f) ; }) ; (map_ident , input_location_id) } HfPlusNode :: FlatMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let flat_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let flat_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , flat_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # flat_map_ident = # input_ident -> flat_map (# f) ; }) ; (flat_map_ident , input_location_id) } HfPlusNode :: Filter { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_ident = # input_ident -> filter (# f) ; }) ; (filter_ident , input_location_id) } HfPlusNode :: FilterMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_map_ident = # input_ident -> filter_map (# f) ; }) ; (filter_map_ident , input_location_id) } HfPlusNode :: Sort (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sort_id = * next_stmt_id ; * next_stmt_id += 1 ; let sort_ident = syn :: Ident :: new (& format ! ("stream_{}" , sort_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # sort_ident = # input_ident -> sort () ; }) ; (sort_ident , input_location_id) } HfPlusNode :: DeferTick (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let defer_tick_id = * next_stmt_id ; * next_stmt_id += 1 ; let defer_tick_ident = syn :: Ident :: new (& format ! ("stream_{}" , defer_tick_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # defer_tick_ident = # input_ident -> defer_tick_lazy () ; }) ; (defer_tick_ident , input_location_id) } HfPlusNode :: Enumerate (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let enumerate_id = * next_stmt_id ; * next_stmt_id += 1 ; let enumerate_ident = syn :: Ident :: new (& format ! ("stream_{}" , enumerate_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # enumerate_ident = # input_ident -> enumerate () ; }) ; (enumerate_ident , input_location_id) } HfPlusNode :: Inspect { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let inspect_id = * next_stmt_id ; * next_stmt_id += 1 ; let inspect_ident = syn :: Ident :: new (& format ! ("stream_{}" , inspect_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # inspect_ident = # input_ident -> inspect (# f) ; }) ; (inspect_ident , input_location_id) } HfPlusNode :: Unique (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let unique_id = * next_stmt_id ; * next_stmt_id += 1 ; let unique_ident = syn :: Ident :: new (& format ! ("stream_{}" , unique_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # unique_ident = # input_ident -> unique ::<'tick > () ; }) ; (unique_ident , input_location_id) } HfPlusNode :: Fold { .. } | HfPlusNode :: FoldKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Fold { .. }) { parse_quote ! (fold) } else { parse_quote ! (fold_keyed) } ; let (HfPlusNode :: Fold { init , acc , input } | HfPlusNode :: FoldKeyed { init , acc , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let fold_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'static > (# init , # acc) ; }) ; } else { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'tick > (# init , # acc) ; }) ; } (fold_ident , input_location_id) } HfPlusNode :: Reduce { .. } | HfPlusNode :: ReduceKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Reduce { .. }) { parse_quote ! (reduce) } else { parse_quote ! (reduce_keyed) } ; let (HfPlusNode :: Reduce { f , input } | HfPlusNode :: ReduceKeyed { f , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let reduce_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'static > (# f) ; }) ; } else { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'tick > (# f) ; }) ; } (reduce_ident , input_location_id) } HfPlusNode :: Network { from_location : _ , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input , } => { let (sink_expr , source_expr , _connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { panic ! ("Expected the network to be finalized") } DebugInstantiate :: Finalized (sink , source , connect_fn) => { (sink , source , connect_fn) } } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sender_builder = graph_builders . entry (input_location_id) . or_default () ; if let Some (serialize_pipeline) = serialize_pipeline { sender_builder . add_statement (parse_quote ! { # input_ident -> # serialize_pipeline -> dest_sink (# sink_expr) ; }) ; } else { sender_builder . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink_expr) ; }) ; } let to_id = match to_location { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let receiver_builder = graph_builders . entry (* to_id) . or_default () ; let receiver_stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let receiver_stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , receiver_stream_id) , Span :: call_site ()) ; if let Some (deserialize_pipeline) = deserialize_pipeline { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) -> # deserialize_pipeline ; }) ; } else { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) ; }) ; } (receiver_stream_ident , * to_id) } } } } } pub mod persist_pullup { pub use std :: cell :: RefCell ; pub use std :: collections :: HashSet ; pub use std :: ops :: Deref ; pub use crate :: ir :: * ; pub fn persist_pullup_node < 'a > (node : & mut HfPlusNode < 'a > , seen_tees : & mut SeenTees < 'a > , persist_pulled_tees : & mut HashSet < * const RefCell < HfPlusNode < 'a > > > ,) { node . transform_children (| n , s | persist_pullup_node (n , s , persist_pulled_tees) , seen_tees ,) ; match node { HfPlusNode :: Unpersist (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Unpersist (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Delta (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Delta (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Tee { inner } => { if persist_pulled_tees . contains (& (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >)) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } else { let inner_borrow = inner . borrow () ; if let HfPlusNode :: Persist (_) = inner_borrow . deref () { drop (inner_borrow) ; persist_pulled_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >) ; if let HfPlusNode :: Persist (box behind_persist) = inner . replace (HfPlusNode :: Placeholder) { * inner . borrow_mut () = behind_persist ; } else { unreachable ! () } * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } } } HfPlusNode :: Map { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Map { f , input : HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Map { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: FlatMap { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: FlatMap { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: FlatMap { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Filter { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Filter { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Filter { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Network { input : box HfPlusNode :: Persist (_) , .. } => { if let HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Union (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Union (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Union (left , right))) ; } else { unreachable ! () } } HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: CrossProduct (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,) ,)))) ; } else { unreachable ! () } } HfPlusNode :: Join (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Join (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: Join (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,))))) ; } else { unreachable ! () } } _ => { } } } pub fn persist_pullup (ir : Vec < HfPlusLeaf >) -> Vec < HfPlusLeaf > { let mut seen_tees = Default :: default () ; let mut persist_pulled_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| n , s | persist_pullup_node (n , s , & mut persist_pulled_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn persist_pullup_through_map () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } # [test] fn persist_pullup_behind_tee () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; let before_tee = flow . source_iter (& process , q ! (0 .. 10)) . tick_batch () . persist () ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } } } pub mod profiler { pub use std :: cell :: RefCell ; pub use hydroflow :: futures :: channel :: mpsc :: UnboundedSender ; pub use stageleft :: * ; pub use crate as hydroflow_plus ; pub use crate :: ir :: * ; pub use crate :: RuntimeContext ; pub fn increment_counter (count : & mut u64) { * count += 1 ; } pub fn quoted_any_fn < 'a , F : Fn (& usize) + 'a , Q : IntoQuotedMut < 'a , F > > (q : Q) -> Q { q } # [doc = " Add a profiling node before each node to count the cardinality of its input"] pub fn add_profiling_node < 'a > (node : & mut HfPlusNode < 'a > , _context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > , id : & mut u32 , seen_tees : & mut SeenTees < 'a > ,) { let my_id = * id ; * id += 1 ; node . transform_children (| node , seen_tees | { add_profiling_node (node , _context , counters , counter_queue , id , seen_tees) } , seen_tees ,) ; let orig_node = std :: mem :: replace (node , HfPlusNode :: Placeholder) ; * node = HfPlusNode :: Inspect { f : quoted_any_fn (q ! ({ counter_queue . borrow () . unbounded_send ((my_id as usize , counters . borrow () [my_id as usize])) . unwrap () ; counters . borrow_mut () [my_id as usize] = 0 ; move | _ | { hydroflow_plus :: profiler :: increment_counter (& mut counters . borrow_mut () [my_id as usize] ,) ; } })) . splice () . into () , input : Box :: new (orig_node) , } } # [doc = " Count the cardinality of each input and periodically output to a file"] pub fn profiling < 'a > (ir : Vec < HfPlusLeaf < 'a > > , context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > ,) -> Vec < HfPlusLeaf < 'a > > { let mut id = 0 ; let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | { add_profiling_node (node , context , counters , counter_queue , & mut id , seen_tees) } , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn profiler_wrapping_all_operators () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let runtime_context = flow . runtime_context () ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (& built . ir ()) ; let counters = RuntimeData :: new ("Fake") ; let counter_queue = RuntimeData :: new ("Fake") ; let pushed_down = built . with_default_optimize () . optimize_with (| ir | super :: profiling (ir , runtime_context , counters , counter_queue)) ; insta :: assert_debug_snapshot ! (& pushed_down . ir ()) ; let _ = pushed_down . compile_no_network :: < MultiGraph > () ; } } } pub mod properties { pub use std :: collections :: HashSet ; pub use stageleft :: * ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , SeenTees } ; pub use crate :: properties :: PropertyDatabase ; # [doc = " Allows us to convert the hydroflow datatype for folds to a binary operation for the algebra"] # [doc = " property tests."] # [allow (dead_code)] pub fn convert_hf_to_binary < I , A : Default , F : Fn (& mut A , I) > (f : F) -> impl Fn (I , I) -> A { move | a , b | { let mut acc = Default :: default () ; f (& mut acc , a) ; f (& mut acc , b) ; acc } } # [cfg (stageleft_macro)] impl PropertyDatabase { # [doc = " Tags the expression as commutative."] pub fn add_commutative_tag < 'a , I , A , F : Fn (& mut A , I) , Q : Quoted < 'a , F > + Clone > (& mut self , expr : Q ,) -> Q { let expr_clone = expr . clone () ; self . commutative . insert (expr_clone . splice ()) ; expr } pub fn is_tagged_commutative (& self , expr : & syn :: Expr) -> bool { self . commutative . contains (expr) } } pub fn properties_optimize_node < 'a > (node : & mut HfPlusNode < 'a > , db : & PropertyDatabase , seen_tees : & mut SeenTees < 'a > ,) { node . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , seen_tees ,) ; match node { HfPlusNode :: ReduceKeyed { f , .. } if db . is_tagged_commutative (& f . 0) => { dbg ! ("IDENTIFIED COMMUTATIVE OPTIMIZATION for {:?}" , & f) ; } _ => { } } } pub fn properties_optimize < 'a > (ir : Vec < HfPlusLeaf < 'a > > , db : & PropertyDatabase ,) -> Vec < HfPlusLeaf < 'a > > { let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use super :: * ; use crate :: deploy :: SingleProcessGraph ; use crate :: FlowBuilder ; # [test] fn test_property_database () { let mut db = PropertyDatabase :: default () ; assert ! (! db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; let _ = db . add_commutative_tag (q ! (| a : & mut i32 , b : i32 | * a += b)) ; assert ! (db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; } # [test] fn test_property_optimized () { let flow = FlowBuilder :: new () ; let mut database = PropertyDatabase :: default () ; let process = flow . process :: < () > () ; let counter_func = q ! (| count : & mut i32 , _ | * count += 1) ; let _ = database . add_commutative_tag (counter_func) ; flow . source_iter (& process , q ! (vec ! [])) . map (q ! (| string : String | (string , ()))) . tick_batch () . fold_keyed (q ! (|| 0) , counter_func) . all_ticks () . for_each (q ! (| (string , count) | println ! ("{}: {}" , string , count))) ; let built = flow . finalize () . optimize_with (| ir | properties_optimize (ir , & database)) . with_default_optimize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let _ = built . compile_no_network :: < SingleProcessGraph > () ; } } } pub use crate :: RuntimeContext ; # [cfg (stageleft_macro)] impl Copy for RuntimeContext < '_ > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Context > for RuntimeContext < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (quote ! (& context))) } } pub use crate :: HfCompiled ; # [cfg (stageleft_macro)] impl < 'a , ID > HfCompiled < 'a , ID > { pub fn hydroflow_ir (& self) -> & BTreeMap < usize , HydroflowGraph > { & self . hydroflow_ir } } # [cfg (stageleft_macro)] impl < 'a > HfCompiled < 'a , usize > { pub fn with_dynamic_id (self , id : impl Quoted < 'a , usize >) -> HfBuiltWithId < 'a > { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; let mut conditioned_tokens = None ; for (subgraph_id , flat_graph) in self . hydroflow_ir { let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; let my_extra_stmts = self . extra_stmts . get (& subgraph_id) . cloned () . unwrap_or_default () ; if let Some (conditioned_tokens) = conditioned_tokens . as_mut () { * conditioned_tokens = syn :: parse_quote ! { # conditioned_tokens else if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } } ; } else { conditioned_tokens = Some (syn :: parse_quote ! { if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } }) ; } } let conditioned_tokens : TokenStream = conditioned_tokens . unwrap () ; let id = id . splice () ; HfBuiltWithId { tokens : syn :: parse_quote ! ({ let __given_id = # id ; # conditioned_tokens else { panic ! ("Invalid node id: {}" , __given_id) ; } }) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfCompiled < 'a , () > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfCompiled < 'a , () > { fn to_tokens (mut self) -> (Option < TokenStream > , Option < TokenStream >) { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; if self . hydroflow_ir . len () != 1 { panic ! ("Expected exactly one subgraph in the Hydroflow IR") ; } let flat_graph = self . hydroflow_ir . remove (& 0) . unwrap () ; let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; (None , Some (tokens)) } } pub use crate :: HfBuiltWithId ; # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfBuiltWithId < 'a > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfBuiltWithId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (self . tokens)) } }
[INFO] [stdout]   |
[INFO] [stdout] help: ...otherwise replace it with an invocation of macro `deref`
[INFO] [stdout]   |
[INFO] [stdout] 1 - pub use std :: collections :: BTreeMap ; pub use std :: marker :: PhantomData ; pub use hydroflow :: scheduled :: context :: Context ; pub use hydroflow :: scheduled :: graph :: Hydroflow ; pub use hydroflow :: * ; pub use lang :: graph :: { partition_graph , HydroflowGraph } ; pub use proc_macro2 :: TokenStream ; pub use quote :: quote ; pub use stageleft :: runtime_support :: FreeVariable ; pub use stageleft :: Quoted ; pub mod runtime_support { pub use bincode ; } pub mod stream { pub use std :: cell :: RefCell ; pub use std :: hash :: Hash ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow :: bytes :: Bytes ; pub use hydroflow :: futures :: Sink ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: quote ; pub use serde :: de :: DeserializeOwned ; pub use serde :: Serialize ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use syn :: parse_quote ; pub use crate :: builder :: { ClusterIds , FlowLeaves } ; pub use crate :: cycle :: { CycleCollection , CycleComplete } ; pub use crate :: ir :: { DebugInstantiate , HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { CanSend , Location , LocationId } ; pub use crate :: { Cluster , Optional , Singleton } ; pub use crate :: stream :: Unbounded ; pub use crate :: stream :: Bounded ; pub use crate :: stream :: NoTick ; pub use crate :: stream :: Tick ; pub use crate :: stream :: Stream ; # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Stream { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Stream < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Stream { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , C , N > > ,) -> Stream < 'a , (T , O) , W , C , N > where O : Clone , { let other : Optional < 'a , O , Bounded , C , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn cross_product < O > (self , other : Stream < 'a , O , W , C , N >) -> Stream < 'a , (T , O) , W , C , N > where T : Clone , O : Clone , { if self . location_kind != other . location_kind { panic ! ("cross_product must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossProduct (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn union (self , other : Stream < 'a , T , W , C , N >) -> Stream < 'a , T , W , C , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn dest_sink < S : Unpin + Sink < T > + 'a > (self , sink : impl Quoted < 'a , S >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: DestSink { sink : sink . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn first (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } # [doc = " Allow this stream through if the other stream has elements, otherwise the output is empty."] pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } # [doc = " Allow this stream through if the other stream is empty, otherwise the output is empty."] pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn enumerate (self) -> Stream < 'a , (usize , T) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Enumerate (Box :: new (self . ir_node . into_inner ())) ,) } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn sort (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Ord , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Sort (Box :: new (self . ir_node . into_inner ())) ,) } pub fn count (self) -> Singleton < 'a , usize , Bounded , Tick , N > { self . fold (q ! (|| 0usize) , q ! (| count , _ | * count += 1)) } pub fn delta (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } pub fn unique (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Eq + Hash , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unique (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn tick_batch (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_prefix (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { self . tick_batch () . persist () } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn for_each < F : Fn (T) + 'a > (self , f : impl IntoQuotedMut < 'a , F >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: ForEach { input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , f : f . splice () . into () , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Unbounded , NoTick , N > { pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . tick_batch () . continue_if (samples . first ()) . all_ticks () } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Unbounded , NoTick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , C , N : Location > Stream < 'a , T , Bounded , C , N > { pub fn filter_not_in (self , other : Stream < 'a , T , Bounded , C , N >) -> Stream < 'a , T , Bounded , C , N > where T : Eq + Hash , { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Difference (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Stream < 'a , & T , W , C , N > { pub fn cloned (self) -> Stream < 'a , T , W , C , N > { self . map (q ! (| d | d . clone ())) } } # [cfg (stageleft_macro)] impl < 'a , K , V1 , W , C , N : Location > Stream < 'a , (K , V1) , W , C , N > { pub fn join < W2 , V2 > (self , n : Stream < 'a , (K , V2) , W2 , C , N > ,) -> Stream < 'a , (K , (V1 , V2)) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Join (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } pub fn anti_join < W2 > (self , n : Stream < 'a , K , W2 , C , N >) -> Stream < 'a , (K , V1) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("anti_join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: AntiJoin (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , K : Eq + Hash , V , N : Location > Stream < 'a , (K , V) , Bounded , Tick , N > { pub fn fold_keyed < A , I : Fn () -> A + 'a , F : Fn (& mut A , V) + 'a > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , A) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FoldKeyed { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce_keyed < F : Fn (& mut V , V) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , V) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: ReduceKeyed { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } pub fn get_this_crate () -> TokenStream { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , Span :: call_site ()) ; quote ! { # ident } } } } pub fn serialize_bincode < T : Serialize > (is_demux : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if is_demux { parse_quote ! { map (| (id , data) | { (id , # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into ()) }) } } else { parse_quote ! { map (| data | { # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into () }) } } } pub fn deserialize_bincode < T : DeserializeOwned > (tagged : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if tagged { parse_quote ! { map (| res | { let (id , b) = res . unwrap () ; (id , # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& b) . unwrap ()) }) } } else { parse_quote ! { map (| res | { # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& res . unwrap ()) . unwrap () }) } } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn send_bincode < N2 : Location , CoreType > (self , other : & N2 ,) -> Stream < 'a , N :: Out < CoreType > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T > , CoreType : Serialize + DeserializeOwned , { let serialize_pipeline = Some (serialize_bincode :: < CoreType > (N :: is_demux ())) ; let deserialize_pipeline = Some (deserialize_bincode :: < CoreType > (N :: is_tagged ())) ; Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bytes < N2 : Location > (self , other : & N2 ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T > , { Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline : None , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline : if N :: is_tagged () { Some (parse_quote ! (map (| (id , b) | (id , b . unwrap () . freeze ())))) } else { Some (parse_quote ! (map (| b | b . unwrap () . freeze ()))) } , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bincode_interleaved < N2 : Location , Tag , CoreType > (self , other : & N2 ,) -> Stream < 'a , CoreType , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T , Out < CoreType > = (Tag , CoreType) > , CoreType : Serialize + DeserializeOwned , { self . send_bincode :: < N2 , CoreType > (other) . map (q ! (| (_ , b) | b)) } pub fn send_bytes_interleaved < N2 : Location , Tag > (self , other : & N2 ,) -> Stream < 'a , Bytes , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T , Out < Bytes > = (Tag , Bytes) > , { self . send_bytes :: < N2 > (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bincode < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < T > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) > , T : Clone + Serialize + DeserializeOwned , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bincode (other) } pub fn broadcast_bincode_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , T , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) , Out < T > = (Tag , T) > + 'a , T : Clone + Serialize + DeserializeOwned , { self . broadcast_bincode (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bytes < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) > + 'a , T : Clone , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bytes (other) } pub fn broadcast_bytes_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , Bytes , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) , Out < Bytes > = (Tag , Bytes) > + 'a , T : Clone , { self . broadcast_bytes (other) . map (q ! (| (_ , b) | b)) } } } pub use stream :: { Bounded , NoTick , Stream , Tick , Unbounded } ; pub mod singleton { pub use std :: cell :: RefCell ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use crate :: builder :: FlowLeaves ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial , CycleComplete } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: Stream ; pub use crate :: singleton :: CrossResult ; # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Singleton < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Singleton :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } pub use crate :: singleton :: Singleton ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Singleton { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleComplete < 'a > for Singleton < 'a , T , Bounded , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleCollectionWithInitial < 'a > for Singleton < 'a , T , Bounded , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , initial : Self , l : LocationId ,) -> Self { Singleton :: new (l , ir_leaves , HfPlusNode :: Union (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , }) , initial . ir_node . into_inner () . into () ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Singleton < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Singleton { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , U , W , C , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (Self :: other_ir_node (other)) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Singleton < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CrossSingleton (Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , Box :: new (HfPlusNode :: Unpersist (Box :: new (Self :: other_ir_node (other)))) ,))) ,) } } pub use crate :: singleton :: Optional ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Optional { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } pub fn some (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: new (singleton . location_kind , singleton . ir_leaves , singleton . ir_node . into_inner () ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > From < Singleton < 'a , T , W , C , N > > for Optional < 'a , T , W , C , N > { fn from (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: some (singleton) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Optional < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Optional { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn into_stream (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , Tick , N > > ,) -> Optional < 'a , (T , O) , Bounded , Tick , N > where O : Clone , { let other : Optional < 'a , O , Bounded , Tick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn union (self , other : Optional < 'a , T , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Optional < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_samples (self) -> Stream < 'a , T , Unbounded , NoTick , N > { self . latest_tick () . all_ticks () } pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . latest_tick () . continue_if (samples . first ()) . latest () . tick_samples () } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Unbounded , NoTick , N > > ,) -> Optional < 'a , (T , O) , Unbounded , NoTick , N > where O : Clone , { let other : Optional < 'a , O , Unbounded , NoTick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } self . latest_tick () . cross_singleton (other . latest_tick ()) . latest () } } } pub use singleton :: { Optional , Singleton } ; pub mod location { pub use std :: marker :: PhantomData ; pub use crate :: location :: LocationId ; pub use crate :: location :: Location ; pub use crate :: location :: Process ; # [cfg (stageleft_macro)] impl < P > Clone for Process < P > { fn clone (& self) -> Self { Process { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < P > Location for Process < P > { fn id (& self) -> LocationId { LocationId :: Process (self . id) } } pub use crate :: location :: Cluster ; # [cfg (stageleft_macro)] impl < C > Clone for Cluster < C > { fn clone (& self) -> Self { Cluster { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < C > Location for Cluster < C > { fn id (& self) -> LocationId { LocationId :: Cluster (self . id) } } pub use crate :: location :: CanSend ; # [cfg (stageleft_macro)] impl < P1 , P2 > CanSend < Process < P2 > > for Process < P1 > { type In < T > = T ; type Out < T > = T ; fn is_demux () -> bool { false } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < P1 , C2 > CanSend < Cluster < C2 > > for Process < P1 > { type In < T > = (u32 , T) ; type Out < T > = T ; fn is_demux () -> bool { true } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < C1 , P2 > CanSend < Process < P2 > > for Cluster < C1 > { type In < T > = T ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { false } fn is_tagged () -> bool { true } } # [cfg (stageleft_macro)] impl < C1 , C2 > CanSend < Cluster < C2 > > for Cluster < C1 > { type In < T > = (u32 , T) ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { true } fn is_tagged () -> bool { true } } } pub use location :: { Cluster , Process } ; pub mod deploy { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use stageleft :: Quoted ; pub mod graphs { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use super :: { LocalDeploy , Node , ProcessSpec } ; pub use crate :: deploy :: graphs :: SingleProcessGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for SingleProcessGraph { type Process = SingleNode ; type Cluster = SingleNode ; type Meta = () ; type GraphId = () ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { SingleNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { SingleNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , SingleProcessGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> SingleNode { SingleNode { } } } pub use crate :: deploy :: graphs :: SingleNode ; # [cfg (stageleft_macro)] impl Node for SingleNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } pub use crate :: deploy :: graphs :: MultiGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for MultiGraph { type Process = MultiNode ; type Cluster = MultiNode ; type Meta = () ; type GraphId = usize ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { MultiNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { MultiNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , MultiGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> MultiNode { MultiNode { } } } pub use crate :: deploy :: graphs :: MultiNode ; # [cfg (stageleft_macro)] impl Node for MultiNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } } pub use graphs :: * ; pub use crate :: deploy :: LocalDeploy ; pub use crate :: deploy :: Deploy ; # [cfg (stageleft_macro)] impl < 'a , T : Deploy < 'a , Process = N , Cluster = C , Meta = M , GraphId = R > , N : Node < Meta = M > , C : Node < Meta = M > , M : Default , R , > LocalDeploy < 'a > for T { type Process = N ; type Cluster = C ; type Meta = M ; type GraphId = R ; fn has_trivial_node () -> bool { < T as Deploy < 'a > > :: has_trivial_node () } fn trivial_process (id : usize) -> Self :: Process { < T as Deploy < 'a > > :: trivial_process (id) } fn trivial_cluster (id : usize) -> Self :: Cluster { < T as Deploy < 'a > > :: trivail_cluster (id) } } pub use crate :: deploy :: ProcessSpec ; pub use crate :: deploy :: ClusterSpec ; pub use crate :: deploy :: Node ; } pub use deploy :: { ClusterSpec , Deploy , ProcessSpec } ; pub mod cycle { pub use std :: marker :: PhantomData ; pub use crate :: builder :: FlowLeaves ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: cycle :: CycleComplete ; pub use crate :: cycle :: CycleCollection ; pub use crate :: cycle :: CycleCollectionWithInitial ; pub use crate :: cycle :: HfCycle ; # [cfg (stageleft_macro)] impl < 'a , S : CycleComplete < 'a > > HfCycle < 'a , S > { pub fn complete (self , stream : S) { let ident = self . ident ; S :: complete (stream , ident) } } } pub use cycle :: HfCycle ; pub mod builder { pub use std :: cell :: RefCell ; pub use std :: collections :: HashMap ; pub use std :: marker :: PhantomData ; pub use std :: rc :: Rc ; pub use std :: time :: Duration ; pub use hydroflow :: futures :: stream :: Stream as FuturesStream ; pub use hydroflow :: { tokio , tokio_stream } ; pub use internal :: TokenStream ; pub use proc_macro2 :: Span ; pub use quote :: quote ; pub use runtime_support :: FreeVariable ; pub use stageleft :: * ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Cluster , Location , LocationId , Process } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: { HfCycle , Optional , RuntimeContext , Singleton , Stream } ; pub mod built { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use hydroflow_lang :: graph :: { eliminate_extra_unions_tees , HydroflowGraph } ; pub use super :: deploy :: { DeployFlow , DeployResult } ; pub use crate :: deploy :: { ClusterSpec , Deploy , LocalDeploy , ProcessSpec } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Cluster , Process } ; pub use crate :: HfCompiled ; pub use crate :: builder :: built :: BuiltFlow ; # [cfg (stageleft_macro)] impl < 'a > Drop for BuiltFlow < 'a > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped BuiltFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn ir (& self) -> & Vec < HfPlusLeaf < 'a > > { & self . ir } pub fn optimize_with (mut self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> BuiltFlow < 'a > { self . used = true ; BuiltFlow { ir : f (std :: mem :: take (& mut self . ir)) , processes : std :: mem :: take (& mut self . processes) , clusters : std :: mem :: take (& mut self . clusters) , used : false , _phantom : PhantomData , } } } pub fn build_inner (ir : & mut Vec < HfPlusLeaf >) -> BTreeMap < usize , HydroflowGraph > { let mut builders = BTreeMap :: new () ; let mut built_tees = HashMap :: new () ; let mut next_stmt_id = 0 ; for leaf in ir { leaf . emit (& mut builders , & mut built_tees , & mut next_stmt_id) ; } builders . into_iter () . map (| (k , v) | { let (mut flat_graph , _ , _) = v . build () ; eliminate_extra_unions_tees (& mut flat_graph) ; (k , flat_graph) }) . collect () } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn compile_no_network < D : LocalDeploy < 'a > > (mut self) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; HfCompiled { hydroflow_ir : build_inner (& mut self . ir) , extra_stmts : BTreeMap :: new () , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> BuiltFlow < 'a > { self . optimize_with (crate :: persist_pullup :: persist_pullup) } fn into_deploy < D : LocalDeploy < 'a > > (mut self) -> DeployFlow < 'a , D > { self . used = true ; let processes = if D :: has_trivial_node () { self . processes . iter () . map (| id | (* id , D :: trivial_process (* id))) . collect () } else { HashMap :: new () } ; let clusters = if D :: has_trivial_node () { self . clusters . iter () . map (| id | (* id , D :: trivial_cluster (* id))) . collect () } else { HashMap :: new () } ; DeployFlow { ir : std :: mem :: take (& mut self . ir) , nodes : processes , clusters , used : false , _phantom : PhantomData , } } pub fn with_process < P , D : LocalDeploy < 'a > > (self , process : & Process < P > , spec : impl ProcessSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_process (process , spec) } pub fn with_cluster < C , D : LocalDeploy < 'a > > (self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_cluster (cluster , spec) } pub fn compile < D : Deploy < 'a > + 'a > (self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . into_deploy :: < D > () . compile (env) } pub fn deploy < D : Deploy < 'a , CompileEnv = () > + 'a > (self , env : & mut D :: InstantiateEnv ,) -> DeployResult < 'a , D > { self . into_deploy :: < D > () . deploy (env) } } } pub mod deploy { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use proc_macro2 :: Span ; pub use stageleft :: Quoted ; pub use super :: built :: build_inner ; pub use crate :: deploy :: { LocalDeploy , Node } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: { Cluster , ClusterSpec , Deploy , HfCompiled , Process , ProcessSpec } ; pub use crate :: builder :: deploy :: DeployFlow ; # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > Drop for DeployFlow < 'a , D > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped DeployFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > DeployFlow < 'a , D > { pub fn with_process < P > (mut self , process : & Process < P > , spec : impl ProcessSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < P > () . to_string () ; self . nodes . insert (process . id , spec . build (process . id , & tag_name)) ; self } pub fn with_cluster < C > (mut self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < C > () . to_string () ; self . clusters . insert (cluster . id , spec . build (cluster . id , & tag_name)) ; self } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployFlow < 'a , D > { pub fn compile (mut self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; let mut seen_tees : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | leaf . compile_network :: < D > (env , & mut seen_tees , & self . nodes , & self . clusters)) . collect () ; let extra_stmts = self . extra_stmts (env) ; HfCompiled { hydroflow_ir : build_inner (& mut ir_leaves_networked) , extra_stmts , _phantom : PhantomData , } } fn extra_stmts (& self , env : & < D as Deploy < 'a > > :: CompileEnv) -> BTreeMap < usize , Vec < syn :: Stmt > > { let all_locations_count = self . nodes . len () + self . clusters . len () ; let mut extra_stmts : BTreeMap < usize , Vec < syn :: Stmt > > = BTreeMap :: new () ; for & c_id in self . clusters . keys () { let self_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , c_id) , Span :: call_site () ,) ; let self_id_expr = D :: cluster_self_id (env) . splice () ; extra_stmts . entry (c_id) . or_default () . push (syn :: parse_quote ! { let # self_id_ident = # self_id_expr ; }) ; for other_location in 0 .. all_locations_count { let other_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , c_id) , Span :: call_site () ,) ; let other_id_expr = D :: cluster_ids (env , c_id) . splice () ; extra_stmts . entry (other_location) . or_default () . push (syn :: parse_quote ! { let # other_id_ident = # other_id_expr ; }) ; } } extra_stmts } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a , CompileEnv = () > > DeployFlow < 'a , D > { # [must_use] pub fn deploy (mut self , env : & mut D :: InstantiateEnv) -> DeployResult < 'a , D > { self . used = true ; let mut seen_tees_instantiate : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | { leaf . compile_network :: < D > (& () , & mut seen_tees_instantiate , & self . nodes , & self . clusters ,) }) . collect () ; let mut compiled = build_inner (& mut ir_leaves_networked) ; let mut extra_stmts = self . extra_stmts (& ()) ; let mut meta = D :: Meta :: default () ; let (mut processes , mut clusters) = (std :: mem :: take (& mut self . nodes) . into_iter () . map (| (node_id , node) | { node . instantiate (env , & mut meta , compiled . remove (& node_id) . unwrap () , extra_stmts . remove (& node_id) . unwrap_or_default () ,) ; (node_id , node) }) . collect :: < HashMap < _ , _ > > () , std :: mem :: take (& mut self . clusters) . into_iter () . map (| (cluster_id , cluster) | { cluster . instantiate (env , & mut meta , compiled . remove (& cluster_id) . unwrap () , extra_stmts . remove (& cluster_id) . unwrap_or_default () ,) ; (cluster_id , cluster) }) . collect :: < HashMap < _ , _ > > () ,) ; for node in processes . values_mut () { node . update_meta (& meta) ; } for cluster in clusters . values_mut () { cluster . update_meta (& meta) ; } let mut seen_tees_connect = HashMap :: new () ; for leaf in ir_leaves_networked { leaf . connect_network (& mut seen_tees_connect) ; } DeployResult { processes , clusters , } } } pub use crate :: builder :: deploy :: DeployResult ; # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployResult < 'a , D > { pub fn get_process < P > (& self , p : & Process < P >) -> & D :: Process { let id = match p . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . processes . get (& id) . unwrap () } pub fn get_cluster < C > (& self , c : & Cluster < C >) -> & D :: Cluster { let id = match c . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . clusters . get (& id) . unwrap () } } } # [doc = " Tracks the leaves of the dataflow IR. This is referenced by"] # [doc = " `Stream` and `HfCycle` to build the IR. The inner option will"] # [doc = " be set to `None` when this builder is finalized."] pub type FlowLeaves < 'a > = Rc < RefCell < Option < Vec < HfPlusLeaf < 'a > > > > > ; pub use crate :: builder :: ClusterIds ; # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Vec < u32 > > for ClusterIds < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , & 'a Vec < u32 > > for ClusterIds < 'a > { } # [derive (Copy , Clone)] pub struct ClusterSelfId < 'a > { pub id : usize , pub _phantom : PhantomData < & 'a mut & 'a u32 > , } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < u32 > for ClusterSelfId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , u32 > for ClusterSelfId < 'a > { } pub use crate :: builder :: FlowBuilder ; # [cfg (stageleft_macro)] impl < 'a > Drop for FlowBuilder < 'a > { fn drop (& mut self) { if ! self . finalized { panic ! ("Dropped FlowBuilder without finalizing, you may have forgotten to call `with_default_optimize`, `optimize_with`, or `finalize`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > QuotedContext for FlowBuilder < 'a > { fn create () -> Self { FlowBuilder :: new () } } # [cfg (stageleft_macro)] impl < 'a > FlowBuilder < 'a > { # [allow (clippy :: new_without_default)] pub fn new () -> FlowBuilder < 'a > { FlowBuilder { ir_leaves : Rc :: new (RefCell :: new (Some (Vec :: new ()))) , nodes : RefCell :: new (vec ! []) , clusters : RefCell :: new (vec ! []) , cycle_ids : RefCell :: new (HashMap :: new ()) , next_node_id : RefCell :: new (0) , finalized : false , _phantom : PhantomData , } } pub fn finalize (mut self) -> built :: BuiltFlow < 'a > { self . finalized = true ; built :: BuiltFlow { ir : self . ir_leaves . borrow_mut () . take () . unwrap () , processes : self . nodes . replace (vec ! []) , clusters : self . clusters . replace (vec ! []) , used : false , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> built :: BuiltFlow < 'a > { self . finalize () . with_default_optimize () } pub fn optimize_with (self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> built :: BuiltFlow < 'a > { self . finalize () . optimize_with (f) } pub fn ir_leaves (& self) -> & FlowLeaves < 'a > { & self . ir_leaves } pub fn process < P > (& self) -> Process < P > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . nodes . borrow_mut () . push (id) ; Process { id , _phantom : PhantomData , } } pub fn cluster < C > (& self) -> Cluster < C > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . clusters . borrow_mut () . push (id) ; Cluster { id , _phantom : PhantomData , } } pub fn runtime_context (& self) -> RuntimeContext < 'a > { RuntimeContext { _phantom : PhantomData , } } pub fn cluster_members < C > (& self , cluster : & Cluster < C > ,) -> impl Quoted < 'a , & 'a Vec < u32 > > + Copy + 'a { ClusterIds { id : cluster . id , _phantom : PhantomData , } } pub fn cluster_self_id < C > (& self , cluster : & Cluster < C >) -> impl Quoted < 'a , u32 > + Copy + 'a { ClusterSelfId { id : cluster . id , _phantom : PhantomData , } } pub fn spin < L : Location > (& self , on : & L) -> Stream < 'a , () , Unbounded , NoTick , L > { Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Spin () , location_kind : on . id () , })) ,) } pub fn spin_batch < L : Location > (& self , on : & L , batch_size : impl Quoted < 'a , usize > + Copy + 'a ,) -> Stream < 'a , () , Bounded , Tick , L > { self . spin (on) . flat_map (q ! (move | _ | 0 .. batch_size)) . map (q ! (| _ | ())) . tick_batch () } pub fn source_stream < T , E : FuturesStream < Item = T > + Unpin , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Unbounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Stream (e . into ()) , location_kind : on . id () , })) ,) } pub fn source_iter < T , E : IntoIterator < Item = T > , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Bounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , })) ,) } pub fn singleton < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Singleton < 'a , T , Bounded , NoTick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Singleton :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,)))) ,) } pub fn singleton_first_tick < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Optional < 'a , T , Bounded , Tick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,) } pub fn source_interval < L : Location > (& self , on : & L , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , () , Unbounded , NoTick , L > { let interval = interval . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : on . id () , })) ,) } pub fn source_interval_delayed < L : Location > (& self , on : & L , delay : impl Quoted < 'a , Duration > + Copy + 'a , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , tokio :: time :: Instant , Unbounded , NoTick , L > { self . source_stream (on , q ! (tokio_stream :: wrappers :: IntervalStream :: new (tokio :: time :: interval_at (tokio :: time :: Instant :: now () + delay , interval))) ,) . tick_batch () . first () . latest () } pub fn cycle < S : CycleCollection < 'a > > (& self , on : & S :: Location) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , on . id ()) ,) } pub fn cycle_with_initial < S : CycleCollectionWithInitial < 'a > > (& self , on : & S :: Location , initial : S ,) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , initial , on . id ()) ,) } } } pub use builder :: FlowBuilder ; pub mod ir { pub use core :: panic ; pub use std :: cell :: RefCell ; pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow_lang :: graph :: FlatGraphBuilder ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: ToTokens ; pub use syn :: parse_quote ; pub use crate :: deploy :: Deploy ; pub use crate :: location :: LocationId ; pub use crate :: ir :: DebugExpr ; # [cfg (stageleft_macro)] impl From < syn :: Expr > for DebugExpr { fn from (expr : syn :: Expr) -> DebugExpr { DebugExpr (expr) } } # [cfg (stageleft_macro)] impl Deref for DebugExpr { type Target = syn :: Expr ; fn deref (& self) -> & Self :: Target { & self . 0 } } # [cfg (stageleft_macro)] impl ToTokens for DebugExpr { fn to_tokens (& self , tokens : & mut TokenStream) { self . 0 . to_tokens (tokens) ; } } # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugExpr { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "{}" , self . 0 . to_token_stream ()) } } pub use crate :: ir :: DebugInstantiate ; # [cfg (stageleft_macro)] impl < 'a > std :: fmt :: Debug for DebugInstantiate < 'a > { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<network instantiate>") } } pub use crate :: ir :: DebugPipelineFn ; # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugPipelineFn { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<function>") } } pub use crate :: ir :: HfPlusSource ; pub use crate :: ir :: HfPlusLeaf ; # [cfg (stageleft_macro)] impl < 'a > HfPlusLeaf < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . compile_network :: < D > (compile_env , s , nodes , clusters) ; } , seen_tees ,) } pub fn connect_network (self , seen_tees : & mut SeenTees < 'a >) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . connect_network (s) ; } , seen_tees ,) } pub fn transform_children (self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) -> HfPlusLeaf < 'a > { match self { HfPlusLeaf :: ForEach { f , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: ForEach { f , input } } HfPlusLeaf :: DestSink { sink , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: DestSink { sink , input } } HfPlusLeaf :: CycleSink { ident , location_kind , mut input , } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: CycleSink { ident , location_kind , input , } } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) { match self { HfPlusLeaf :: ForEach { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> for_each (# f) ; }) ; } HfPlusLeaf :: DestSink { sink , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink) ; }) ; } HfPlusLeaf :: CycleSink { ident , location_kind , input , } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; assert_eq ! (input_location_id , * location_id , "cycle_sink location mismatch") ; graph_builders . entry (* location_id) . or_default () . add_statement (parse_quote ! { # ident = # input_ident ; }) ; } } } } pub use crate :: ir :: HfPlusNode ; pub type SeenTees < 'a > = HashMap < * const RefCell < HfPlusNode < 'a > > , Rc < RefCell < HfPlusNode < 'a > > > > ; # [cfg (stageleft_macro)] impl < 'a > HfPlusNode < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (& mut self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) { self . transform_children (| n , s | n . compile_network :: < D > (compile_env , s , nodes , clusters) , seen_tees ,) ; if let HfPlusNode :: Network { from_location , to_location , instantiate_fn , .. } = self { let (sink_expr , source_expr , connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { let ((sink , source) , connect_fn) = match (from_location , to_location) { (LocationId :: Process (from) , LocationId :: Process (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: o2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Process (from) , LocationId :: Cluster (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: o2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Process (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: m2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Cluster (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: m2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } } ; (sink , source , connect_fn) } DebugInstantiate :: Finalized (_ , _ , _) => panic ! ("network already finalized") , } ; * instantiate_fn = DebugInstantiate :: Finalized (sink_expr , source_expr , connect_fn) ; } } pub fn connect_network (& mut self , seen_tees : & mut SeenTees < 'a >) { self . transform_children (| n , s | n . connect_network (s) , seen_tees) ; if let HfPlusNode :: Network { instantiate_fn , .. } = self { match instantiate_fn { DebugInstantiate :: Building () => panic ! ("network not built") , DebugInstantiate :: Finalized (_ , _ , ref connect_fn) => { connect_fn () ; } } } } pub fn transform_children (& mut self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) { match self { HfPlusNode :: Placeholder => { panic ! () ; } HfPlusNode :: Source { .. } => { } HfPlusNode :: CycleSource { .. } => { } HfPlusNode :: Tee { inner } => { if let Some (transformed) = seen_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { * inner = transformed . clone () ; } else { let transformed_cell = Rc :: new (RefCell :: new (HfPlusNode :: Placeholder)) ; seen_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , transformed_cell . clone () ,) ; let mut orig = inner . replace (HfPlusNode :: Placeholder) ; transform (& mut orig , seen_tees) ; * transformed_cell . borrow_mut () = orig ; * inner = transformed_cell ; } } HfPlusNode :: Persist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Unpersist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Delta (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Union (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossProduct (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossSingleton (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Join (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Difference (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: AntiJoin (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Map { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FlatMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Filter { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FilterMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Sort (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: DeferTick (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Enumerate (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Inspect { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Unique (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Fold { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FoldKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Reduce { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: ReduceKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Network { input , .. } => { transform (input . as_mut () , seen_tees) ; } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) -> (syn :: Ident , usize) { match self { HfPlusNode :: Placeholder => { panic ! () } HfPlusNode :: Persist (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let persist_id = * next_stmt_id ; * next_stmt_id += 1 ; let persist_ident = syn :: Ident :: new (& format ! ("stream_{}" , persist_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # persist_ident = # inner_ident -> persist ::<'static > () ; }) ; (persist_ident , location) } HfPlusNode :: Unpersist (_) => { panic ! ("Unpersist is a marker node and should have been optimized away. This is likely a compiler bug.") } HfPlusNode :: Delta (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let delta_id = * next_stmt_id ; * next_stmt_id += 1 ; let delta_ident = syn :: Ident :: new (& format ! ("stream_{}" , delta_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # delta_ident = # inner_ident -> multiset_delta () ; }) ; (delta_ident , location) } HfPlusNode :: Source { source , location_kind , } => { let source_id = * next_stmt_id ; * next_stmt_id += 1 ; let source_ident = syn :: Ident :: new (& format ! ("stream_{}" , source_id) , Span :: call_site ()) ; let source_stmt = match source { HfPlusSource :: Stream (expr) => { parse_quote ! { # source_ident = source_stream (# expr) ; } } HfPlusSource :: Iter (expr) => { parse_quote ! { # source_ident = source_iter (# expr) ; } } HfPlusSource :: Interval (expr) => { parse_quote ! { # source_ident = source_interval (# expr) ; } } HfPlusSource :: Spin () => { parse_quote ! { # source_ident = spin () ; } } } ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; graph_builders . entry (* location_id) . or_default () . add_statement (source_stmt) ; (source_ident , * location_id) } HfPlusNode :: CycleSource { ident , location_kind , } => { let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; (ident . clone () , * location_id) } HfPlusNode :: Tee { inner } => { if let Some (ret) = built_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { ret . clone () } else { let (inner_ident , inner_location_id) = inner . borrow () . emit (graph_builders , built_tees , next_stmt_id) ; let tee_id = * next_stmt_id ; * next_stmt_id += 1 ; let tee_ident = syn :: Ident :: new (& format ! ("stream_{}" , tee_id) , Span :: call_site ()) ; let builder = graph_builders . entry (inner_location_id) . or_default () ; builder . add_statement (parse_quote ! { # tee_ident = # inner_ident -> tee () ; }) ; built_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , (tee_ident . clone () , inner_location_id) ,) ; (tee_ident , inner_location_id) } } HfPlusNode :: Union (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "union inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let union_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # union_ident = union () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [0] # union_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # union_ident ; }) ; (union_ident , left_location_id) } HfPlusNode :: CrossSingleton (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "cross_singleton inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let cross_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # cross_ident = cross_singleton () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [input] # cross_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [single] # cross_ident ; }) ; (cross_ident , left_location_id) } HfPlusNode :: CrossProduct (..) | HfPlusNode :: Join (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: CrossProduct (..)) { parse_quote ! (cross_join_multiset) } else { parse_quote ! (join_multiset) } ; let (HfPlusNode :: CrossProduct (left , right) | HfPlusNode :: Join (left , right)) = self else { unreachable ! () } ; let (left_inner , left_was_persist) = if let HfPlusNode :: Persist (left) = left . as_ref () { (left , true) } else { (left , false) } ; let (right_inner , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left_inner . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right_inner . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "join / cross product inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; match (left_was_persist , right_was_persist) { (true , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'static > () ; }) ; } (true , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'tick > () ; }) ; } (false , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } (false , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } } ; builder . add_statement (parse_quote ! { # left_ident -> [0] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Difference (..) | HfPlusNode :: AntiJoin (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Difference (..)) { parse_quote ! (difference_multiset) } else { parse_quote ! (anti_join_multiset) } ; let (HfPlusNode :: Difference (left , right) | HfPlusNode :: AntiJoin (left , right)) = self else { unreachable ! () } ; let (right , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "difference / anti join inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; if right_was_persist { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } else { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } builder . add_statement (parse_quote ! { # left_ident -> [pos] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [neg] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Map { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let map_id = * next_stmt_id ; * next_stmt_id += 1 ; let map_ident = syn :: Ident :: new (& format ! ("stream_{}" , map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # map_ident = # input_ident -> map (# f) ; }) ; (map_ident , input_location_id) } HfPlusNode :: FlatMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let flat_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let flat_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , flat_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # flat_map_ident = # input_ident -> flat_map (# f) ; }) ; (flat_map_ident , input_location_id) } HfPlusNode :: Filter { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_ident = # input_ident -> filter (# f) ; }) ; (filter_ident , input_location_id) } HfPlusNode :: FilterMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_map_ident = # input_ident -> filter_map (# f) ; }) ; (filter_map_ident , input_location_id) } HfPlusNode :: Sort (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sort_id = * next_stmt_id ; * next_stmt_id += 1 ; let sort_ident = syn :: Ident :: new (& format ! ("stream_{}" , sort_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # sort_ident = # input_ident -> sort () ; }) ; (sort_ident , input_location_id) } HfPlusNode :: DeferTick (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let defer_tick_id = * next_stmt_id ; * next_stmt_id += 1 ; let defer_tick_ident = syn :: Ident :: new (& format ! ("stream_{}" , defer_tick_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # defer_tick_ident = # input_ident -> defer_tick_lazy () ; }) ; (defer_tick_ident , input_location_id) } HfPlusNode :: Enumerate (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let enumerate_id = * next_stmt_id ; * next_stmt_id += 1 ; let enumerate_ident = syn :: Ident :: new (& format ! ("stream_{}" , enumerate_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # enumerate_ident = # input_ident -> enumerate () ; }) ; (enumerate_ident , input_location_id) } HfPlusNode :: Inspect { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let inspect_id = * next_stmt_id ; * next_stmt_id += 1 ; let inspect_ident = syn :: Ident :: new (& format ! ("stream_{}" , inspect_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # inspect_ident = # input_ident -> inspect (# f) ; }) ; (inspect_ident , input_location_id) } HfPlusNode :: Unique (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let unique_id = * next_stmt_id ; * next_stmt_id += 1 ; let unique_ident = syn :: Ident :: new (& format ! ("stream_{}" , unique_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # unique_ident = # input_ident -> unique ::<'tick > () ; }) ; (unique_ident , input_location_id) } HfPlusNode :: Fold { .. } | HfPlusNode :: FoldKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Fold { .. }) { parse_quote ! (fold) } else { parse_quote ! (fold_keyed) } ; let (HfPlusNode :: Fold { init , acc , input } | HfPlusNode :: FoldKeyed { init , acc , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let fold_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'static > (# init , # acc) ; }) ; } else { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'tick > (# init , # acc) ; }) ; } (fold_ident , input_location_id) } HfPlusNode :: Reduce { .. } | HfPlusNode :: ReduceKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Reduce { .. }) { parse_quote ! (reduce) } else { parse_quote ! (reduce_keyed) } ; let (HfPlusNode :: Reduce { f , input } | HfPlusNode :: ReduceKeyed { f , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let reduce_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'static > (# f) ; }) ; } else { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'tick > (# f) ; }) ; } (reduce_ident , input_location_id) } HfPlusNode :: Network { from_location : _ , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input , } => { let (sink_expr , source_expr , _connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { panic ! ("Expected the network to be finalized") } DebugInstantiate :: Finalized (sink , source , connect_fn) => { (sink , source , connect_fn) } } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sender_builder = graph_builders . entry (input_location_id) . or_default () ; if let Some (serialize_pipeline) = serialize_pipeline { sender_builder . add_statement (parse_quote ! { # input_ident -> # serialize_pipeline -> dest_sink (# sink_expr) ; }) ; } else { sender_builder . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink_expr) ; }) ; } let to_id = match to_location { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let receiver_builder = graph_builders . entry (* to_id) . or_default () ; let receiver_stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let receiver_stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , receiver_stream_id) , Span :: call_site ()) ; if let Some (deserialize_pipeline) = deserialize_pipeline { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) -> # deserialize_pipeline ; }) ; } else { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) ; }) ; } (receiver_stream_ident , * to_id) } } } } } pub mod persist_pullup { pub use std :: cell :: RefCell ; pub use std :: collections :: HashSet ; pub use std :: ops :: Deref ; pub use crate :: ir :: * ; pub fn persist_pullup_node < 'a > (node : & mut HfPlusNode < 'a > , seen_tees : & mut SeenTees < 'a > , persist_pulled_tees : & mut HashSet < * const RefCell < HfPlusNode < 'a > > > ,) { node . transform_children (| n , s | persist_pullup_node (n , s , persist_pulled_tees) , seen_tees ,) ; match node { HfPlusNode :: Unpersist (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Unpersist (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Delta (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Delta (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Tee { inner } => { if persist_pulled_tees . contains (& (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >)) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } else { let inner_borrow = inner . borrow () ; if let HfPlusNode :: Persist (_) = inner_borrow . deref () { drop (inner_borrow) ; persist_pulled_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >) ; if let HfPlusNode :: Persist (box behind_persist) = inner . replace (HfPlusNode :: Placeholder) { * inner . borrow_mut () = behind_persist ; } else { unreachable ! () } * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } } } HfPlusNode :: Map { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Map { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Map { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: FlatMap { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: FlatMap { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: FlatMap { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Filter { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Filter { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Filter { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Network { input : box HfPlusNode :: Persist (_) , .. } => { if let HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Union (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Union (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Union (left , right))) ; } else { unreachable ! () } } HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: CrossProduct (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,) ,)))) ; } else { unreachable ! () } } HfPlusNode :: Join (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Join (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: Join (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,))))) ; } else { unreachable ! () } } _ => { } } } pub fn persist_pullup (ir : Vec < HfPlusLeaf >) -> Vec < HfPlusLeaf > { let mut seen_tees = Default :: default () ; let mut persist_pulled_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| n , s | persist_pullup_node (n , s , & mut persist_pulled_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn persist_pullup_through_map () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } # [test] fn persist_pullup_behind_tee () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; let before_tee = flow . source_iter (& process , q ! (0 .. 10)) . tick_batch () . persist () ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } } } pub mod profiler { pub use std :: cell :: RefCell ; pub use hydroflow :: futures :: channel :: mpsc :: UnboundedSender ; pub use stageleft :: * ; pub use crate as hydroflow_plus ; pub use crate :: ir :: * ; pub use crate :: RuntimeContext ; pub fn increment_counter (count : & mut u64) { * count += 1 ; } pub fn quoted_any_fn < 'a , F : Fn (& usize) + 'a , Q : IntoQuotedMut < 'a , F > > (q : Q) -> Q { q } # [doc = " Add a profiling node before each node to count the cardinality of its input"] pub fn add_profiling_node < 'a > (node : & mut HfPlusNode < 'a > , _context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > , id : & mut u32 , seen_tees : & mut SeenTees < 'a > ,) { let my_id = * id ; * id += 1 ; node . transform_children (| node , seen_tees | { add_profiling_node (node , _context , counters , counter_queue , id , seen_tees) } , seen_tees ,) ; let orig_node = std :: mem :: replace (node , HfPlusNode :: Placeholder) ; * node = HfPlusNode :: Inspect { f : quoted_any_fn (q ! ({ counter_queue . borrow () . unbounded_send ((my_id as usize , counters . borrow () [my_id as usize])) . unwrap () ; counters . borrow_mut () [my_id as usize] = 0 ; move | _ | { hydroflow_plus :: profiler :: increment_counter (& mut counters . borrow_mut () [my_id as usize] ,) ; } })) . splice () . into () , input : Box :: new (orig_node) , } } # [doc = " Count the cardinality of each input and periodically output to a file"] pub fn profiling < 'a > (ir : Vec < HfPlusLeaf < 'a > > , context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > ,) -> Vec < HfPlusLeaf < 'a > > { let mut id = 0 ; let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | { add_profiling_node (node , context , counters , counter_queue , & mut id , seen_tees) } , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn profiler_wrapping_all_operators () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let runtime_context = flow . runtime_context () ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (& built . ir ()) ; let counters = RuntimeData :: new ("Fake") ; let counter_queue = RuntimeData :: new ("Fake") ; let pushed_down = built . with_default_optimize () . optimize_with (| ir | super :: profiling (ir , runtime_context , counters , counter_queue)) ; insta :: assert_debug_snapshot ! (& pushed_down . ir ()) ; let _ = pushed_down . compile_no_network :: < MultiGraph > () ; } } } pub mod properties { pub use std :: collections :: HashSet ; pub use stageleft :: * ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , SeenTees } ; pub use crate :: properties :: PropertyDatabase ; # [doc = " Allows us to convert the hydroflow datatype for folds to a binary operation for the algebra"] # [doc = " property tests."] # [allow (dead_code)] pub fn convert_hf_to_binary < I , A : Default , F : Fn (& mut A , I) > (f : F) -> impl Fn (I , I) -> A { move | a , b | { let mut acc = Default :: default () ; f (& mut acc , a) ; f (& mut acc , b) ; acc } } # [cfg (stageleft_macro)] impl PropertyDatabase { # [doc = " Tags the expression as commutative."] pub fn add_commutative_tag < 'a , I , A , F : Fn (& mut A , I) , Q : Quoted < 'a , F > + Clone > (& mut self , expr : Q ,) -> Q { let expr_clone = expr . clone () ; self . commutative . insert (expr_clone . splice ()) ; expr } pub fn is_tagged_commutative (& self , expr : & syn :: Expr) -> bool { self . commutative . contains (expr) } } pub fn properties_optimize_node < 'a > (node : & mut HfPlusNode < 'a > , db : & PropertyDatabase , seen_tees : & mut SeenTees < 'a > ,) { node . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , seen_tees ,) ; match node { HfPlusNode :: ReduceKeyed { f , .. } if db . is_tagged_commutative (& f . 0) => { dbg ! ("IDENTIFIED COMMUTATIVE OPTIMIZATION for {:?}" , & f) ; } _ => { } } } pub fn properties_optimize < 'a > (ir : Vec < HfPlusLeaf < 'a > > , db : & PropertyDatabase ,) -> Vec < HfPlusLeaf < 'a > > { let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use super :: * ; use crate :: deploy :: SingleProcessGraph ; use crate :: FlowBuilder ; # [test] fn test_property_database () { let mut db = PropertyDatabase :: default () ; assert ! (! db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; let _ = db . add_commutative_tag (q ! (| a : & mut i32 , b : i32 | * a += b)) ; assert ! (db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; } # [test] fn test_property_optimized () { let flow = FlowBuilder :: new () ; let mut database = PropertyDatabase :: default () ; let process = flow . process :: < () > () ; let counter_func = q ! (| count : & mut i32 , _ | * count += 1) ; let _ = database . add_commutative_tag (counter_func) ; flow . source_iter (& process , q ! (vec ! [])) . map (q ! (| string : String | (string , ()))) . tick_batch () . fold_keyed (q ! (|| 0) , counter_func) . all_ticks () . for_each (q ! (| (string , count) | println ! ("{}: {}" , string , count))) ; let built = flow . finalize () . optimize_with (| ir | properties_optimize (ir , & database)) . with_default_optimize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let _ = built . compile_no_network :: < SingleProcessGraph > () ; } } } pub use crate :: RuntimeContext ; # [cfg (stageleft_macro)] impl Copy for RuntimeContext < '_ > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Context > for RuntimeContext < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (quote ! (& context))) } } pub use crate :: HfCompiled ; # [cfg (stageleft_macro)] impl < 'a , ID > HfCompiled < 'a , ID > { pub fn hydroflow_ir (& self) -> & BTreeMap < usize , HydroflowGraph > { & self . hydroflow_ir } } # [cfg (stageleft_macro)] impl < 'a > HfCompiled < 'a , usize > { pub fn with_dynamic_id (self , id : impl Quoted < 'a , usize >) -> HfBuiltWithId < 'a > { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; let mut conditioned_tokens = None ; for (subgraph_id , flat_graph) in self . hydroflow_ir { let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; let my_extra_stmts = self . extra_stmts . get (& subgraph_id) . cloned () . unwrap_or_default () ; if let Some (conditioned_tokens) = conditioned_tokens . as_mut () { * conditioned_tokens = syn :: parse_quote ! { # conditioned_tokens else if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } } ; } else { conditioned_tokens = Some (syn :: parse_quote ! { if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } }) ; } } let conditioned_tokens : TokenStream = conditioned_tokens . unwrap () ; let id = id . splice () ; HfBuiltWithId { tokens : syn :: parse_quote ! ({ let __given_id = # id ; # conditioned_tokens else { panic ! ("Invalid node id: {}" , __given_id) ; } }) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfCompiled < 'a , () > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfCompiled < 'a , () > { fn to_tokens (mut self) -> (Option < TokenStream > , Option < TokenStream >) { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; if self . hydroflow_ir . len () != 1 { panic ! ("Expected exactly one subgraph in the Hydroflow IR") ; } let flat_graph = self . hydroflow_ir . remove (& 0) . unwrap () ; let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; (None , Some (tokens)) } } pub use crate :: HfBuiltWithId ; # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfBuiltWithId < 'a > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfBuiltWithId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (self . tokens)) } }
[INFO] [stdout] 1 + pub use std :: collections :: BTreeMap ; pub use std :: marker :: PhantomData ; pub use hydroflow :: scheduled :: context :: Context ; pub use hydroflow :: scheduled :: graph :: Hydroflow ; pub use hydroflow :: * ; pub use lang :: graph :: { partition_graph , HydroflowGraph } ; pub use proc_macro2 :: TokenStream ; pub use quote :: quote ; pub use stageleft :: runtime_support :: FreeVariable ; pub use stageleft :: Quoted ; pub mod runtime_support { pub use bincode ; } pub mod stream { pub use std :: cell :: RefCell ; pub use std :: hash :: Hash ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow :: bytes :: Bytes ; pub use hydroflow :: futures :: Sink ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: quote ; pub use serde :: de :: DeserializeOwned ; pub use serde :: Serialize ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use syn :: parse_quote ; pub use crate :: builder :: { ClusterIds , FlowLeaves } ; pub use crate :: cycle :: { CycleCollection , CycleComplete } ; pub use crate :: ir :: { DebugInstantiate , HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { CanSend , Location , LocationId } ; pub use crate :: { Cluster , Optional , Singleton } ; pub use crate :: stream :: Unbounded ; pub use crate :: stream :: Bounded ; pub use crate :: stream :: NoTick ; pub use crate :: stream :: Tick ; pub use crate :: stream :: Stream ; # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Stream { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Stream < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Stream { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , C , N > > ,) -> Stream < 'a , (T , O) , W , C , N > where O : Clone , { let other : Optional < 'a , O , Bounded , C , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn cross_product < O > (self , other : Stream < 'a , O , W , C , N >) -> Stream < 'a , (T , O) , W , C , N > where T : Clone , O : Clone , { if self . location_kind != other . location_kind { panic ! ("cross_product must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossProduct (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn union (self , other : Stream < 'a , T , W , C , N >) -> Stream < 'a , T , W , C , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn dest_sink < S : Unpin + Sink < T > + 'a > (self , sink : impl Quoted < 'a , S >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: DestSink { sink : sink . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn first (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } # [doc = " Allow this stream through if the other stream has elements, otherwise the output is empty."] pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } # [doc = " Allow this stream through if the other stream is empty, otherwise the output is empty."] pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn enumerate (self) -> Stream < 'a , (usize , T) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Enumerate (Box :: new (self . ir_node . into_inner ())) ,) } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn sort (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Ord , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Sort (Box :: new (self . ir_node . into_inner ())) ,) } pub fn count (self) -> Singleton < 'a , usize , Bounded , Tick , N > { self . fold (q ! (|| 0usize) , q ! (| count , _ | * count += 1)) } pub fn delta (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } pub fn unique (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Eq + Hash , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unique (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn tick_batch (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_prefix (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { self . tick_batch () . persist () } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn for_each < F : Fn (T) + 'a > (self , f : impl IntoQuotedMut < 'a , F >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: ForEach { input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , f : f . splice () . into () , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Unbounded , NoTick , N > { pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . tick_batch () . continue_if (samples . first ()) . all_ticks () } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Unbounded , NoTick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , C , N : Location > Stream < 'a , T , Bounded , C , N > { pub fn filter_not_in (self , other : Stream < 'a , T , Bounded , C , N >) -> Stream < 'a , T , Bounded , C , N > where T : Eq + Hash , { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Difference (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Stream < 'a , & T , W , C , N > { pub fn cloned (self) -> Stream < 'a , T , W , C , N > { self . map (q ! (| d | d . clone ())) } } # [cfg (stageleft_macro)] impl < 'a , K , V1 , W , C , N : Location > Stream < 'a , (K , V1) , W , C , N > { pub fn join < W2 , V2 > (self , n : Stream < 'a , (K , V2) , W2 , C , N > ,) -> Stream < 'a , (K , (V1 , V2)) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Join (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } pub fn anti_join < W2 > (self , n : Stream < 'a , K , W2 , C , N >) -> Stream < 'a , (K , V1) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("anti_join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: AntiJoin (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , K : Eq + Hash , V , N : Location > Stream < 'a , (K , V) , Bounded , Tick , N > { pub fn fold_keyed < A , I : Fn () -> A + 'a , F : Fn (& mut A , V) + 'a > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , A) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FoldKeyed { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce_keyed < F : Fn (& mut V , V) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , V) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: ReduceKeyed { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } pub fn get_this_crate () -> TokenStream { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , Span :: call_site ()) ; quote ! { # ident } } } } pub fn serialize_bincode < T : Serialize > (is_demux : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if is_demux { parse_quote ! { map (| (id , data) | { (id , # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into ()) }) } } else { parse_quote ! { map (| data | { # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into () }) } } } pub fn deserialize_bincode < T : DeserializeOwned > (tagged : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if tagged { parse_quote ! { map (| res | { let (id , b) = res . unwrap () ; (id , # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& b) . unwrap ()) }) } } else { parse_quote ! { map (| res | { # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& res . unwrap ()) . unwrap () }) } } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn send_bincode < N2 : Location , CoreType > (self , other : & N2 ,) -> Stream < 'a , N :: Out < CoreType > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T > , CoreType : Serialize + DeserializeOwned , { let serialize_pipeline = Some (serialize_bincode :: < CoreType > (N :: is_demux ())) ; let deserialize_pipeline = Some (deserialize_bincode :: < CoreType > (N :: is_tagged ())) ; Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bytes < N2 : Location > (self , other : & N2 ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T > , { Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline : None , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline : if N :: is_tagged () { Some (parse_quote ! (map (| (id , b) | (id , b . unwrap () . freeze ())))) } else { Some (parse_quote ! (map (| b | b . unwrap () . freeze ()))) } , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bincode_interleaved < N2 : Location , Tag , CoreType > (self , other : & N2 ,) -> Stream < 'a , CoreType , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T , Out < CoreType > = (Tag , CoreType) > , CoreType : Serialize + DeserializeOwned , { self . send_bincode :: < N2 , CoreType > (other) . map (q ! (| (_ , b) | b)) } pub fn send_bytes_interleaved < N2 : Location , Tag > (self , other : & N2 ,) -> Stream < 'a , Bytes , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T , Out < Bytes > = (Tag , Bytes) > , { self . send_bytes :: < N2 > (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bincode < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < T > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) > , T : Clone + Serialize + DeserializeOwned , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bincode (other) } pub fn broadcast_bincode_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , T , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) , Out < T > = (Tag , T) > + 'a , T : Clone + Serialize + DeserializeOwned , { self . broadcast_bincode (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bytes < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) > + 'a , T : Clone , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bytes (other) } pub fn broadcast_bytes_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , Bytes , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) , Out < Bytes > = (Tag , Bytes) > + 'a , T : Clone , { self . broadcast_bytes (other) . map (q ! (| (_ , b) | b)) } } } pub use stream :: { Bounded , NoTick , Stream , Tick , Unbounded } ; pub mod singleton { pub use std :: cell :: RefCell ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use crate :: builder :: FlowLeaves ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial , CycleComplete } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: Stream ; pub use crate :: singleton :: CrossResult ; # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Singleton < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Singleton :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } pub use crate :: singleton :: Singleton ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Singleton { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleComplete < 'a > for Singleton < 'a , T , Bounded , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleCollectionWithInitial < 'a > for Singleton < 'a , T , Bounded , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , initial : Self , l : LocationId ,) -> Self { Singleton :: new (l , ir_leaves , HfPlusNode :: Union (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , }) , initial . ir_node . into_inner () . into () ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Singleton < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Singleton { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , U , W , C , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (Self :: other_ir_node (other)) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Singleton < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CrossSingleton (Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , Box :: new (HfPlusNode :: Unpersist (Box :: new (Self :: other_ir_node (other)))) ,))) ,) } } pub use crate :: singleton :: Optional ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Optional { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } pub fn some (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: new (singleton . location_kind , singleton . ir_leaves , singleton . ir_node . into_inner () ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > From < Singleton < 'a , T , W , C , N > > for Optional < 'a , T , W , C , N > { fn from (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: some (singleton) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Optional < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Optional { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn into_stream (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , Tick , N > > ,) -> Optional < 'a , (T , O) , Bounded , Tick , N > where O : Clone , { let other : Optional < 'a , O , Bounded , Tick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn union (self , other : Optional < 'a , T , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Optional < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_samples (self) -> Stream < 'a , T , Unbounded , NoTick , N > { self . latest_tick () . all_ticks () } pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . latest_tick () . continue_if (samples . first ()) . latest () . tick_samples () } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Unbounded , NoTick , N > > ,) -> Optional < 'a , (T , O) , Unbounded , NoTick , N > where O : Clone , { let other : Optional < 'a , O , Unbounded , NoTick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } self . latest_tick () . cross_singleton (other . latest_tick ()) . latest () } } } pub use singleton :: { Optional , Singleton } ; pub mod location { pub use std :: marker :: PhantomData ; pub use crate :: location :: LocationId ; pub use crate :: location :: Location ; pub use crate :: location :: Process ; # [cfg (stageleft_macro)] impl < P > Clone for Process < P > { fn clone (& self) -> Self { Process { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < P > Location for Process < P > { fn id (& self) -> LocationId { LocationId :: Process (self . id) } } pub use crate :: location :: Cluster ; # [cfg (stageleft_macro)] impl < C > Clone for Cluster < C > { fn clone (& self) -> Self { Cluster { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < C > Location for Cluster < C > { fn id (& self) -> LocationId { LocationId :: Cluster (self . id) } } pub use crate :: location :: CanSend ; # [cfg (stageleft_macro)] impl < P1 , P2 > CanSend < Process < P2 > > for Process < P1 > { type In < T > = T ; type Out < T > = T ; fn is_demux () -> bool { false } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < P1 , C2 > CanSend < Cluster < C2 > > for Process < P1 > { type In < T > = (u32 , T) ; type Out < T > = T ; fn is_demux () -> bool { true } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < C1 , P2 > CanSend < Process < P2 > > for Cluster < C1 > { type In < T > = T ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { false } fn is_tagged () -> bool { true } } # [cfg (stageleft_macro)] impl < C1 , C2 > CanSend < Cluster < C2 > > for Cluster < C1 > { type In < T > = (u32 , T) ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { true } fn is_tagged () -> bool { true } } } pub use location :: { Cluster , Process } ; pub mod deploy { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use stageleft :: Quoted ; pub mod graphs { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use super :: { LocalDeploy , Node , ProcessSpec } ; pub use crate :: deploy :: graphs :: SingleProcessGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for SingleProcessGraph { type Process = SingleNode ; type Cluster = SingleNode ; type Meta = () ; type GraphId = () ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { SingleNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { SingleNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , SingleProcessGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> SingleNode { SingleNode { } } } pub use crate :: deploy :: graphs :: SingleNode ; # [cfg (stageleft_macro)] impl Node for SingleNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } pub use crate :: deploy :: graphs :: MultiGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for MultiGraph { type Process = MultiNode ; type Cluster = MultiNode ; type Meta = () ; type GraphId = usize ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { MultiNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { MultiNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , MultiGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> MultiNode { MultiNode { } } } pub use crate :: deploy :: graphs :: MultiNode ; # [cfg (stageleft_macro)] impl Node for MultiNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } } pub use graphs :: * ; pub use crate :: deploy :: LocalDeploy ; pub use crate :: deploy :: Deploy ; # [cfg (stageleft_macro)] impl < 'a , T : Deploy < 'a , Process = N , Cluster = C , Meta = M , GraphId = R > , N : Node < Meta = M > , C : Node < Meta = M > , M : Default , R , > LocalDeploy < 'a > for T { type Process = N ; type Cluster = C ; type Meta = M ; type GraphId = R ; fn has_trivial_node () -> bool { < T as Deploy < 'a > > :: has_trivial_node () } fn trivial_process (id : usize) -> Self :: Process { < T as Deploy < 'a > > :: trivial_process (id) } fn trivial_cluster (id : usize) -> Self :: Cluster { < T as Deploy < 'a > > :: trivail_cluster (id) } } pub use crate :: deploy :: ProcessSpec ; pub use crate :: deploy :: ClusterSpec ; pub use crate :: deploy :: Node ; } pub use deploy :: { ClusterSpec , Deploy , ProcessSpec } ; pub mod cycle { pub use std :: marker :: PhantomData ; pub use crate :: builder :: FlowLeaves ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: cycle :: CycleComplete ; pub use crate :: cycle :: CycleCollection ; pub use crate :: cycle :: CycleCollectionWithInitial ; pub use crate :: cycle :: HfCycle ; # [cfg (stageleft_macro)] impl < 'a , S : CycleComplete < 'a > > HfCycle < 'a , S > { pub fn complete (self , stream : S) { let ident = self . ident ; S :: complete (stream , ident) } } } pub use cycle :: HfCycle ; pub mod builder { pub use std :: cell :: RefCell ; pub use std :: collections :: HashMap ; pub use std :: marker :: PhantomData ; pub use std :: rc :: Rc ; pub use std :: time :: Duration ; pub use hydroflow :: futures :: stream :: Stream as FuturesStream ; pub use hydroflow :: { tokio , tokio_stream } ; pub use internal :: TokenStream ; pub use proc_macro2 :: Span ; pub use quote :: quote ; pub use runtime_support :: FreeVariable ; pub use stageleft :: * ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Cluster , Location , LocationId , Process } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: { HfCycle , Optional , RuntimeContext , Singleton , Stream } ; pub mod built { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use hydroflow_lang :: graph :: { eliminate_extra_unions_tees , HydroflowGraph } ; pub use super :: deploy :: { DeployFlow , DeployResult } ; pub use crate :: deploy :: { ClusterSpec , Deploy , LocalDeploy , ProcessSpec } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Cluster , Process } ; pub use crate :: HfCompiled ; pub use crate :: builder :: built :: BuiltFlow ; # [cfg (stageleft_macro)] impl < 'a > Drop for BuiltFlow < 'a > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped BuiltFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn ir (& self) -> & Vec < HfPlusLeaf < 'a > > { & self . ir } pub fn optimize_with (mut self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> BuiltFlow < 'a > { self . used = true ; BuiltFlow { ir : f (std :: mem :: take (& mut self . ir)) , processes : std :: mem :: take (& mut self . processes) , clusters : std :: mem :: take (& mut self . clusters) , used : false , _phantom : PhantomData , } } } pub fn build_inner (ir : & mut Vec < HfPlusLeaf >) -> BTreeMap < usize , HydroflowGraph > { let mut builders = BTreeMap :: new () ; let mut built_tees = HashMap :: new () ; let mut next_stmt_id = 0 ; for leaf in ir { leaf . emit (& mut builders , & mut built_tees , & mut next_stmt_id) ; } builders . into_iter () . map (| (k , v) | { let (mut flat_graph , _ , _) = v . build () ; eliminate_extra_unions_tees (& mut flat_graph) ; (k , flat_graph) }) . collect () } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn compile_no_network < D : LocalDeploy < 'a > > (mut self) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; HfCompiled { hydroflow_ir : build_inner (& mut self . ir) , extra_stmts : BTreeMap :: new () , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> BuiltFlow < 'a > { self . optimize_with (crate :: persist_pullup :: persist_pullup) } fn into_deploy < D : LocalDeploy < 'a > > (mut self) -> DeployFlow < 'a , D > { self . used = true ; let processes = if D :: has_trivial_node () { self . processes . iter () . map (| id | (* id , D :: trivial_process (* id))) . collect () } else { HashMap :: new () } ; let clusters = if D :: has_trivial_node () { self . clusters . iter () . map (| id | (* id , D :: trivial_cluster (* id))) . collect () } else { HashMap :: new () } ; DeployFlow { ir : std :: mem :: take (& mut self . ir) , nodes : processes , clusters , used : false , _phantom : PhantomData , } } pub fn with_process < P , D : LocalDeploy < 'a > > (self , process : & Process < P > , spec : impl ProcessSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_process (process , spec) } pub fn with_cluster < C , D : LocalDeploy < 'a > > (self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_cluster (cluster , spec) } pub fn compile < D : Deploy < 'a > + 'a > (self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . into_deploy :: < D > () . compile (env) } pub fn deploy < D : Deploy < 'a , CompileEnv = () > + 'a > (self , env : & mut D :: InstantiateEnv ,) -> DeployResult < 'a , D > { self . into_deploy :: < D > () . deploy (env) } } } pub mod deploy { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use proc_macro2 :: Span ; pub use stageleft :: Quoted ; pub use super :: built :: build_inner ; pub use crate :: deploy :: { LocalDeploy , Node } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: { Cluster , ClusterSpec , Deploy , HfCompiled , Process , ProcessSpec } ; pub use crate :: builder :: deploy :: DeployFlow ; # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > Drop for DeployFlow < 'a , D > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped DeployFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > DeployFlow < 'a , D > { pub fn with_process < P > (mut self , process : & Process < P > , spec : impl ProcessSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < P > () . to_string () ; self . nodes . insert (process . id , spec . build (process . id , & tag_name)) ; self } pub fn with_cluster < C > (mut self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < C > () . to_string () ; self . clusters . insert (cluster . id , spec . build (cluster . id , & tag_name)) ; self } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployFlow < 'a , D > { pub fn compile (mut self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; let mut seen_tees : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | leaf . compile_network :: < D > (env , & mut seen_tees , & self . nodes , & self . clusters)) . collect () ; let extra_stmts = self . extra_stmts (env) ; HfCompiled { hydroflow_ir : build_inner (& mut ir_leaves_networked) , extra_stmts , _phantom : PhantomData , } } fn extra_stmts (& self , env : & < D as Deploy < 'a > > :: CompileEnv) -> BTreeMap < usize , Vec < syn :: Stmt > > { let all_locations_count = self . nodes . len () + self . clusters . len () ; let mut extra_stmts : BTreeMap < usize , Vec < syn :: Stmt > > = BTreeMap :: new () ; for & c_id in self . clusters . keys () { let self_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , c_id) , Span :: call_site () ,) ; let self_id_expr = D :: cluster_self_id (env) . splice () ; extra_stmts . entry (c_id) . or_default () . push (syn :: parse_quote ! { let # self_id_ident = # self_id_expr ; }) ; for other_location in 0 .. all_locations_count { let other_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , c_id) , Span :: call_site () ,) ; let other_id_expr = D :: cluster_ids (env , c_id) . splice () ; extra_stmts . entry (other_location) . or_default () . push (syn :: parse_quote ! { let # other_id_ident = # other_id_expr ; }) ; } } extra_stmts } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a , CompileEnv = () > > DeployFlow < 'a , D > { # [must_use] pub fn deploy (mut self , env : & mut D :: InstantiateEnv) -> DeployResult < 'a , D > { self . used = true ; let mut seen_tees_instantiate : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | { leaf . compile_network :: < D > (& () , & mut seen_tees_instantiate , & self . nodes , & self . clusters ,) }) . collect () ; let mut compiled = build_inner (& mut ir_leaves_networked) ; let mut extra_stmts = self . extra_stmts (& ()) ; let mut meta = D :: Meta :: default () ; let (mut processes , mut clusters) = (std :: mem :: take (& mut self . nodes) . into_iter () . map (| (node_id , node) | { node . instantiate (env , & mut meta , compiled . remove (& node_id) . unwrap () , extra_stmts . remove (& node_id) . unwrap_or_default () ,) ; (node_id , node) }) . collect :: < HashMap < _ , _ > > () , std :: mem :: take (& mut self . clusters) . into_iter () . map (| (cluster_id , cluster) | { cluster . instantiate (env , & mut meta , compiled . remove (& cluster_id) . unwrap () , extra_stmts . remove (& cluster_id) . unwrap_or_default () ,) ; (cluster_id , cluster) }) . collect :: < HashMap < _ , _ > > () ,) ; for node in processes . values_mut () { node . update_meta (& meta) ; } for cluster in clusters . values_mut () { cluster . update_meta (& meta) ; } let mut seen_tees_connect = HashMap :: new () ; for leaf in ir_leaves_networked { leaf . connect_network (& mut seen_tees_connect) ; } DeployResult { processes , clusters , } } } pub use crate :: builder :: deploy :: DeployResult ; # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployResult < 'a , D > { pub fn get_process < P > (& self , p : & Process < P >) -> & D :: Process { let id = match p . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . processes . get (& id) . unwrap () } pub fn get_cluster < C > (& self , c : & Cluster < C >) -> & D :: Cluster { let id = match c . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . clusters . get (& id) . unwrap () } } } # [doc = " Tracks the leaves of the dataflow IR. This is referenced by"] # [doc = " `Stream` and `HfCycle` to build the IR. The inner option will"] # [doc = " be set to `None` when this builder is finalized."] pub type FlowLeaves < 'a > = Rc < RefCell < Option < Vec < HfPlusLeaf < 'a > > > > > ; pub use crate :: builder :: ClusterIds ; # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Vec < u32 > > for ClusterIds < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , & 'a Vec < u32 > > for ClusterIds < 'a > { } # [derive (Copy , Clone)] pub struct ClusterSelfId < 'a > { pub id : usize , pub _phantom : PhantomData < & 'a mut & 'a u32 > , } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < u32 > for ClusterSelfId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , u32 > for ClusterSelfId < 'a > { } pub use crate :: builder :: FlowBuilder ; # [cfg (stageleft_macro)] impl < 'a > Drop for FlowBuilder < 'a > { fn drop (& mut self) { if ! self . finalized { panic ! ("Dropped FlowBuilder without finalizing, you may have forgotten to call `with_default_optimize`, `optimize_with`, or `finalize`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > QuotedContext for FlowBuilder < 'a > { fn create () -> Self { FlowBuilder :: new () } } # [cfg (stageleft_macro)] impl < 'a > FlowBuilder < 'a > { # [allow (clippy :: new_without_default)] pub fn new () -> FlowBuilder < 'a > { FlowBuilder { ir_leaves : Rc :: new (RefCell :: new (Some (Vec :: new ()))) , nodes : RefCell :: new (vec ! []) , clusters : RefCell :: new (vec ! []) , cycle_ids : RefCell :: new (HashMap :: new ()) , next_node_id : RefCell :: new (0) , finalized : false , _phantom : PhantomData , } } pub fn finalize (mut self) -> built :: BuiltFlow < 'a > { self . finalized = true ; built :: BuiltFlow { ir : self . ir_leaves . borrow_mut () . take () . unwrap () , processes : self . nodes . replace (vec ! []) , clusters : self . clusters . replace (vec ! []) , used : false , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> built :: BuiltFlow < 'a > { self . finalize () . with_default_optimize () } pub fn optimize_with (self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> built :: BuiltFlow < 'a > { self . finalize () . optimize_with (f) } pub fn ir_leaves (& self) -> & FlowLeaves < 'a > { & self . ir_leaves } pub fn process < P > (& self) -> Process < P > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . nodes . borrow_mut () . push (id) ; Process { id , _phantom : PhantomData , } } pub fn cluster < C > (& self) -> Cluster < C > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . clusters . borrow_mut () . push (id) ; Cluster { id , _phantom : PhantomData , } } pub fn runtime_context (& self) -> RuntimeContext < 'a > { RuntimeContext { _phantom : PhantomData , } } pub fn cluster_members < C > (& self , cluster : & Cluster < C > ,) -> impl Quoted < 'a , & 'a Vec < u32 > > + Copy + 'a { ClusterIds { id : cluster . id , _phantom : PhantomData , } } pub fn cluster_self_id < C > (& self , cluster : & Cluster < C >) -> impl Quoted < 'a , u32 > + Copy + 'a { ClusterSelfId { id : cluster . id , _phantom : PhantomData , } } pub fn spin < L : Location > (& self , on : & L) -> Stream < 'a , () , Unbounded , NoTick , L > { Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Spin () , location_kind : on . id () , })) ,) } pub fn spin_batch < L : Location > (& self , on : & L , batch_size : impl Quoted < 'a , usize > + Copy + 'a ,) -> Stream < 'a , () , Bounded , Tick , L > { self . spin (on) . flat_map (q ! (move | _ | 0 .. batch_size)) . map (q ! (| _ | ())) . tick_batch () } pub fn source_stream < T , E : FuturesStream < Item = T > + Unpin , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Unbounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Stream (e . into ()) , location_kind : on . id () , })) ,) } pub fn source_iter < T , E : IntoIterator < Item = T > , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Bounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , })) ,) } pub fn singleton < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Singleton < 'a , T , Bounded , NoTick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Singleton :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,)))) ,) } pub fn singleton_first_tick < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Optional < 'a , T , Bounded , Tick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,) } pub fn source_interval < L : Location > (& self , on : & L , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , () , Unbounded , NoTick , L > { let interval = interval . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : on . id () , })) ,) } pub fn source_interval_delayed < L : Location > (& self , on : & L , delay : impl Quoted < 'a , Duration > + Copy + 'a , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , tokio :: time :: Instant , Unbounded , NoTick , L > { self . source_stream (on , q ! (tokio_stream :: wrappers :: IntervalStream :: new (tokio :: time :: interval_at (tokio :: time :: Instant :: now () + delay , interval))) ,) . tick_batch () . first () . latest () } pub fn cycle < S : CycleCollection < 'a > > (& self , on : & S :: Location) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , on . id ()) ,) } pub fn cycle_with_initial < S : CycleCollectionWithInitial < 'a > > (& self , on : & S :: Location , initial : S ,) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , initial , on . id ()) ,) } } } pub use builder :: FlowBuilder ; pub mod ir { pub use core :: panic ; pub use std :: cell :: RefCell ; pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow_lang :: graph :: FlatGraphBuilder ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: ToTokens ; pub use syn :: parse_quote ; pub use crate :: deploy :: Deploy ; pub use crate :: location :: LocationId ; pub use crate :: ir :: DebugExpr ; # [cfg (stageleft_macro)] impl From < syn :: Expr > for DebugExpr { fn from (expr : syn :: Expr) -> DebugExpr { DebugExpr (expr) } } # [cfg (stageleft_macro)] impl Deref for DebugExpr { type Target = syn :: Expr ; fn deref (& self) -> & Self :: Target { & self . 0 } } # [cfg (stageleft_macro)] impl ToTokens for DebugExpr { fn to_tokens (& self , tokens : & mut TokenStream) { self . 0 . to_tokens (tokens) ; } } # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugExpr { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "{}" , self . 0 . to_token_stream ()) } } pub use crate :: ir :: DebugInstantiate ; # [cfg (stageleft_macro)] impl < 'a > std :: fmt :: Debug for DebugInstantiate < 'a > { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<network instantiate>") } } pub use crate :: ir :: DebugPipelineFn ; # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugPipelineFn { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<function>") } } pub use crate :: ir :: HfPlusSource ; pub use crate :: ir :: HfPlusLeaf ; # [cfg (stageleft_macro)] impl < 'a > HfPlusLeaf < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . compile_network :: < D > (compile_env , s , nodes , clusters) ; } , seen_tees ,) } pub fn connect_network (self , seen_tees : & mut SeenTees < 'a >) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . connect_network (s) ; } , seen_tees ,) } pub fn transform_children (self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) -> HfPlusLeaf < 'a > { match self { HfPlusLeaf :: ForEach { f , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: ForEach { f , input } } HfPlusLeaf :: DestSink { sink , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: DestSink { sink , input } } HfPlusLeaf :: CycleSink { ident , location_kind , mut input , } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: CycleSink { ident , location_kind , input , } } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) { match self { HfPlusLeaf :: ForEach { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> for_each (# f) ; }) ; } HfPlusLeaf :: DestSink { sink , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink) ; }) ; } HfPlusLeaf :: CycleSink { ident , location_kind , input , } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; assert_eq ! (input_location_id , * location_id , "cycle_sink location mismatch") ; graph_builders . entry (* location_id) . or_default () . add_statement (parse_quote ! { # ident = # input_ident ; }) ; } } } } pub use crate :: ir :: HfPlusNode ; pub type SeenTees < 'a > = HashMap < * const RefCell < HfPlusNode < 'a > > , Rc < RefCell < HfPlusNode < 'a > > > > ; # [cfg (stageleft_macro)] impl < 'a > HfPlusNode < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (& mut self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) { self . transform_children (| n , s | n . compile_network :: < D > (compile_env , s , nodes , clusters) , seen_tees ,) ; if let HfPlusNode :: Network { from_location , to_location , instantiate_fn , .. } = self { let (sink_expr , source_expr , connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { let ((sink , source) , connect_fn) = match (from_location , to_location) { (LocationId :: Process (from) , LocationId :: Process (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: o2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Process (from) , LocationId :: Cluster (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: o2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Process (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: m2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Cluster (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: m2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } } ; (sink , source , connect_fn) } DebugInstantiate :: Finalized (_ , _ , _) => panic ! ("network already finalized") , } ; * instantiate_fn = DebugInstantiate :: Finalized (sink_expr , source_expr , connect_fn) ; } } pub fn connect_network (& mut self , seen_tees : & mut SeenTees < 'a >) { self . transform_children (| n , s | n . connect_network (s) , seen_tees) ; if let HfPlusNode :: Network { instantiate_fn , .. } = self { match instantiate_fn { DebugInstantiate :: Building () => panic ! ("network not built") , DebugInstantiate :: Finalized (_ , _ , ref connect_fn) => { connect_fn () ; } } } } pub fn transform_children (& mut self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) { match self { HfPlusNode :: Placeholder => { panic ! () ; } HfPlusNode :: Source { .. } => { } HfPlusNode :: CycleSource { .. } => { } HfPlusNode :: Tee { inner } => { if let Some (transformed) = seen_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { * inner = transformed . clone () ; } else { let transformed_cell = Rc :: new (RefCell :: new (HfPlusNode :: Placeholder)) ; seen_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , transformed_cell . clone () ,) ; let mut orig = inner . replace (HfPlusNode :: Placeholder) ; transform (& mut orig , seen_tees) ; * transformed_cell . borrow_mut () = orig ; * inner = transformed_cell ; } } HfPlusNode :: Persist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Unpersist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Delta (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Union (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossProduct (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossSingleton (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Join (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Difference (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: AntiJoin (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Map { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FlatMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Filter { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FilterMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Sort (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: DeferTick (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Enumerate (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Inspect { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Unique (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Fold { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FoldKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Reduce { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: ReduceKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Network { input , .. } => { transform (input . as_mut () , seen_tees) ; } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) -> (syn :: Ident , usize) { match self { HfPlusNode :: Placeholder => { panic ! () } HfPlusNode :: Persist (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let persist_id = * next_stmt_id ; * next_stmt_id += 1 ; let persist_ident = syn :: Ident :: new (& format ! ("stream_{}" , persist_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # persist_ident = # inner_ident -> persist ::<'static > () ; }) ; (persist_ident , location) } HfPlusNode :: Unpersist (_) => { panic ! ("Unpersist is a marker node and should have been optimized away. This is likely a compiler bug.") } HfPlusNode :: Delta (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let delta_id = * next_stmt_id ; * next_stmt_id += 1 ; let delta_ident = syn :: Ident :: new (& format ! ("stream_{}" , delta_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # delta_ident = # inner_ident -> multiset_delta () ; }) ; (delta_ident , location) } HfPlusNode :: Source { source , location_kind , } => { let source_id = * next_stmt_id ; * next_stmt_id += 1 ; let source_ident = syn :: Ident :: new (& format ! ("stream_{}" , source_id) , Span :: call_site ()) ; let source_stmt = match source { HfPlusSource :: Stream (expr) => { parse_quote ! { # source_ident = source_stream (# expr) ; } } HfPlusSource :: Iter (expr) => { parse_quote ! { # source_ident = source_iter (# expr) ; } } HfPlusSource :: Interval (expr) => { parse_quote ! { # source_ident = source_interval (# expr) ; } } HfPlusSource :: Spin () => { parse_quote ! { # source_ident = spin () ; } } } ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; graph_builders . entry (* location_id) . or_default () . add_statement (source_stmt) ; (source_ident , * location_id) } HfPlusNode :: CycleSource { ident , location_kind , } => { let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; (ident . clone () , * location_id) } HfPlusNode :: Tee { inner } => { if let Some (ret) = built_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { ret . clone () } else { let (inner_ident , inner_location_id) = inner . borrow () . emit (graph_builders , built_tees , next_stmt_id) ; let tee_id = * next_stmt_id ; * next_stmt_id += 1 ; let tee_ident = syn :: Ident :: new (& format ! ("stream_{}" , tee_id) , Span :: call_site ()) ; let builder = graph_builders . entry (inner_location_id) . or_default () ; builder . add_statement (parse_quote ! { # tee_ident = # inner_ident -> tee () ; }) ; built_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , (tee_ident . clone () , inner_location_id) ,) ; (tee_ident , inner_location_id) } } HfPlusNode :: Union (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "union inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let union_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # union_ident = union () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [0] # union_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # union_ident ; }) ; (union_ident , left_location_id) } HfPlusNode :: CrossSingleton (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "cross_singleton inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let cross_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # cross_ident = cross_singleton () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [input] # cross_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [single] # cross_ident ; }) ; (cross_ident , left_location_id) } HfPlusNode :: CrossProduct (..) | HfPlusNode :: Join (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: CrossProduct (..)) { parse_quote ! (cross_join_multiset) } else { parse_quote ! (join_multiset) } ; let (HfPlusNode :: CrossProduct (left , right) | HfPlusNode :: Join (left , right)) = self else { unreachable ! () } ; let (left_inner , left_was_persist) = if let HfPlusNode :: Persist (left) = left . as_ref () { (left , true) } else { (left , false) } ; let (right_inner , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left_inner . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right_inner . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "join / cross product inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; match (left_was_persist , right_was_persist) { (true , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'static > () ; }) ; } (true , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'tick > () ; }) ; } (false , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } (false , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } } ; builder . add_statement (parse_quote ! { # left_ident -> [0] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Difference (..) | HfPlusNode :: AntiJoin (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Difference (..)) { parse_quote ! (difference_multiset) } else { parse_quote ! (anti_join_multiset) } ; let (HfPlusNode :: Difference (left , right) | HfPlusNode :: AntiJoin (left , right)) = self else { unreachable ! () } ; let (right , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "difference / anti join inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; if right_was_persist { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } else { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } builder . add_statement (parse_quote ! { # left_ident -> [pos] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [neg] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Map { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let map_id = * next_stmt_id ; * next_stmt_id += 1 ; let map_ident = syn :: Ident :: new (& format ! ("stream_{}" , map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # map_ident = # input_ident -> map (# f) ; }) ; (map_ident , input_location_id) } HfPlusNode :: FlatMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let flat_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let flat_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , flat_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # flat_map_ident = # input_ident -> flat_map (# f) ; }) ; (flat_map_ident , input_location_id) } HfPlusNode :: Filter { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_ident = # input_ident -> filter (# f) ; }) ; (filter_ident , input_location_id) } HfPlusNode :: FilterMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_map_ident = # input_ident -> filter_map (# f) ; }) ; (filter_map_ident , input_location_id) } HfPlusNode :: Sort (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sort_id = * next_stmt_id ; * next_stmt_id += 1 ; let sort_ident = syn :: Ident :: new (& format ! ("stream_{}" , sort_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # sort_ident = # input_ident -> sort () ; }) ; (sort_ident , input_location_id) } HfPlusNode :: DeferTick (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let defer_tick_id = * next_stmt_id ; * next_stmt_id += 1 ; let defer_tick_ident = syn :: Ident :: new (& format ! ("stream_{}" , defer_tick_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # defer_tick_ident = # input_ident -> defer_tick_lazy () ; }) ; (defer_tick_ident , input_location_id) } HfPlusNode :: Enumerate (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let enumerate_id = * next_stmt_id ; * next_stmt_id += 1 ; let enumerate_ident = syn :: Ident :: new (& format ! ("stream_{}" , enumerate_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # enumerate_ident = # input_ident -> enumerate () ; }) ; (enumerate_ident , input_location_id) } HfPlusNode :: Inspect { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let inspect_id = * next_stmt_id ; * next_stmt_id += 1 ; let inspect_ident = syn :: Ident :: new (& format ! ("stream_{}" , inspect_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # inspect_ident = # input_ident -> inspect (# f) ; }) ; (inspect_ident , input_location_id) } HfPlusNode :: Unique (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let unique_id = * next_stmt_id ; * next_stmt_id += 1 ; let unique_ident = syn :: Ident :: new (& format ! ("stream_{}" , unique_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # unique_ident = # input_ident -> unique ::<'tick > () ; }) ; (unique_ident , input_location_id) } HfPlusNode :: Fold { .. } | HfPlusNode :: FoldKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Fold { .. }) { parse_quote ! (fold) } else { parse_quote ! (fold_keyed) } ; let (HfPlusNode :: Fold { init , acc , input } | HfPlusNode :: FoldKeyed { init , acc , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let fold_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'static > (# init , # acc) ; }) ; } else { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'tick > (# init , # acc) ; }) ; } (fold_ident , input_location_id) } HfPlusNode :: Reduce { .. } | HfPlusNode :: ReduceKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Reduce { .. }) { parse_quote ! (reduce) } else { parse_quote ! (reduce_keyed) } ; let (HfPlusNode :: Reduce { f , input } | HfPlusNode :: ReduceKeyed { f , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let reduce_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'static > (# f) ; }) ; } else { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'tick > (# f) ; }) ; } (reduce_ident , input_location_id) } HfPlusNode :: Network { from_location : _ , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input , } => { let (sink_expr , source_expr , _connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { panic ! ("Expected the network to be finalized") } DebugInstantiate :: Finalized (sink , source , connect_fn) => { (sink , source , connect_fn) } } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sender_builder = graph_builders . entry (input_location_id) . or_default () ; if let Some (serialize_pipeline) = serialize_pipeline { sender_builder . add_statement (parse_quote ! { # input_ident -> # serialize_pipeline -> dest_sink (# sink_expr) ; }) ; } else { sender_builder . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink_expr) ; }) ; } let to_id = match to_location { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let receiver_builder = graph_builders . entry (* to_id) . or_default () ; let receiver_stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let receiver_stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , receiver_stream_id) , Span :: call_site ()) ; if let Some (deserialize_pipeline) = deserialize_pipeline { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) -> # deserialize_pipeline ; }) ; } else { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) ; }) ; } (receiver_stream_ident , * to_id) } } } } } pub mod persist_pullup { pub use std :: cell :: RefCell ; pub use std :: collections :: HashSet ; pub use std :: ops :: Deref ; pub use crate :: ir :: * ; pub fn persist_pullup_node < 'a > (node : & mut HfPlusNode < 'a > , seen_tees : & mut SeenTees < 'a > , persist_pulled_tees : & mut HashSet < * const RefCell < HfPlusNode < 'a > > > ,) { node . transform_children (| n , s | persist_pullup_node (n , s , persist_pulled_tees) , seen_tees ,) ; match node { HfPlusNode :: Unpersist (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Unpersist (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Delta (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Delta (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Tee { inner } => { if persist_pulled_tees . contains (& (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >)) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } else { let inner_borrow = inner . borrow () ; if let HfPlusNode :: Persist (_) = inner_borrow . deref () { drop (inner_borrow) ; persist_pulled_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >) ; if let HfPlusNode :: Persist (box behind_persist) = inner . replace (HfPlusNode :: Placeholder) { * inner . borrow_mut () = behind_persist ; } else { unreachable ! () } * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } } } HfPlusNode :: Map { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Map { f , input : deref!(HfPlusNode :: Persist (behind_persist)) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Map { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: FlatMap { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: FlatMap { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: FlatMap { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Filter { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Filter { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Filter { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Network { input : box HfPlusNode :: Persist (_) , .. } => { if let HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Union (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Union (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Union (left , right))) ; } else { unreachable ! () } } HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: CrossProduct (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,) ,)))) ; } else { unreachable ! () } } HfPlusNode :: Join (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Join (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: Join (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,))))) ; } else { unreachable ! () } } _ => { } } } pub fn persist_pullup (ir : Vec < HfPlusLeaf >) -> Vec < HfPlusLeaf > { let mut seen_tees = Default :: default () ; let mut persist_pulled_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| n , s | persist_pullup_node (n , s , & mut persist_pulled_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn persist_pullup_through_map () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } # [test] fn persist_pullup_behind_tee () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; let before_tee = flow . source_iter (& process , q ! (0 .. 10)) . tick_batch () . persist () ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } } } pub mod profiler { pub use std :: cell :: RefCell ; pub use hydroflow :: futures :: channel :: mpsc :: UnboundedSender ; pub use stageleft :: * ; pub use crate as hydroflow_plus ; pub use crate :: ir :: * ; pub use crate :: RuntimeContext ; pub fn increment_counter (count : & mut u64) { * count += 1 ; } pub fn quoted_any_fn < 'a , F : Fn (& usize) + 'a , Q : IntoQuotedMut < 'a , F > > (q : Q) -> Q { q } # [doc = " Add a profiling node before each node to count the cardinality of its input"] pub fn add_profiling_node < 'a > (node : & mut HfPlusNode < 'a > , _context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > , id : & mut u32 , seen_tees : & mut SeenTees < 'a > ,) { let my_id = * id ; * id += 1 ; node . transform_children (| node , seen_tees | { add_profiling_node (node , _context , counters , counter_queue , id , seen_tees) } , seen_tees ,) ; let orig_node = std :: mem :: replace (node , HfPlusNode :: Placeholder) ; * node = HfPlusNode :: Inspect { f : quoted_any_fn (q ! ({ counter_queue . borrow () . unbounded_send ((my_id as usize , counters . borrow () [my_id as usize])) . unwrap () ; counters . borrow_mut () [my_id as usize] = 0 ; move | _ | { hydroflow_plus :: profiler :: increment_counter (& mut counters . borrow_mut () [my_id as usize] ,) ; } })) . splice () . into () , input : Box :: new (orig_node) , } } # [doc = " Count the cardinality of each input and periodically output to a file"] pub fn profiling < 'a > (ir : Vec < HfPlusLeaf < 'a > > , context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > ,) -> Vec < HfPlusLeaf < 'a > > { let mut id = 0 ; let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | { add_profiling_node (node , context , counters , counter_queue , & mut id , seen_tees) } , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn profiler_wrapping_all_operators () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let runtime_context = flow . runtime_context () ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (& built . ir ()) ; let counters = RuntimeData :: new ("Fake") ; let counter_queue = RuntimeData :: new ("Fake") ; let pushed_down = built . with_default_optimize () . optimize_with (| ir | super :: profiling (ir , runtime_context , counters , counter_queue)) ; insta :: assert_debug_snapshot ! (& pushed_down . ir ()) ; let _ = pushed_down . compile_no_network :: < MultiGraph > () ; } } } pub mod properties { pub use std :: collections :: HashSet ; pub use stageleft :: * ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , SeenTees } ; pub use crate :: properties :: PropertyDatabase ; # [doc = " Allows us to convert the hydroflow datatype for folds to a binary operation for the algebra"] # [doc = " property tests."] # [allow (dead_code)] pub fn convert_hf_to_binary < I , A : Default , F : Fn (& mut A , I) > (f : F) -> impl Fn (I , I) -> A { move | a , b | { let mut acc = Default :: default () ; f (& mut acc , a) ; f (& mut acc , b) ; acc } } # [cfg (stageleft_macro)] impl PropertyDatabase { # [doc = " Tags the expression as commutative."] pub fn add_commutative_tag < 'a , I , A , F : Fn (& mut A , I) , Q : Quoted < 'a , F > + Clone > (& mut self , expr : Q ,) -> Q { let expr_clone = expr . clone () ; self . commutative . insert (expr_clone . splice ()) ; expr } pub fn is_tagged_commutative (& self , expr : & syn :: Expr) -> bool { self . commutative . contains (expr) } } pub fn properties_optimize_node < 'a > (node : & mut HfPlusNode < 'a > , db : & PropertyDatabase , seen_tees : & mut SeenTees < 'a > ,) { node . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , seen_tees ,) ; match node { HfPlusNode :: ReduceKeyed { f , .. } if db . is_tagged_commutative (& f . 0) => { dbg ! ("IDENTIFIED COMMUTATIVE OPTIMIZATION for {:?}" , & f) ; } _ => { } } } pub fn properties_optimize < 'a > (ir : Vec < HfPlusLeaf < 'a > > , db : & PropertyDatabase ,) -> Vec < HfPlusLeaf < 'a > > { let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use super :: * ; use crate :: deploy :: SingleProcessGraph ; use crate :: FlowBuilder ; # [test] fn test_property_database () { let mut db = PropertyDatabase :: default () ; assert ! (! db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; let _ = db . add_commutative_tag (q ! (| a : & mut i32 , b : i32 | * a += b)) ; assert ! (db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; } # [test] fn test_property_optimized () { let flow = FlowBuilder :: new () ; let mut database = PropertyDatabase :: default () ; let process = flow . process :: < () > () ; let counter_func = q ! (| count : & mut i32 , _ | * count += 1) ; let _ = database . add_commutative_tag (counter_func) ; flow . source_iter (& process , q ! (vec ! [])) . map (q ! (| string : String | (string , ()))) . tick_batch () . fold_keyed (q ! (|| 0) , counter_func) . all_ticks () . for_each (q ! (| (string , count) | println ! ("{}: {}" , string , count))) ; let built = flow . finalize () . optimize_with (| ir | properties_optimize (ir , & database)) . with_default_optimize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let _ = built . compile_no_network :: < SingleProcessGraph > () ; } } } pub use crate :: RuntimeContext ; # [cfg (stageleft_macro)] impl Copy for RuntimeContext < '_ > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Context > for RuntimeContext < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (quote ! (& context))) } } pub use crate :: HfCompiled ; # [cfg (stageleft_macro)] impl < 'a , ID > HfCompiled < 'a , ID > { pub fn hydroflow_ir (& self) -> & BTreeMap < usize , HydroflowGraph > { & self . hydroflow_ir } } # [cfg (stageleft_macro)] impl < 'a > HfCompiled < 'a , usize > { pub fn with_dynamic_id (self , id : impl Quoted < 'a , usize >) -> HfBuiltWithId < 'a > { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; let mut conditioned_tokens = None ; for (subgraph_id , flat_graph) in self . hydroflow_ir { let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; let my_extra_stmts = self . extra_stmts . get (& subgraph_id) . cloned () . unwrap_or_default () ; if let Some (conditioned_tokens) = conditioned_tokens . as_mut () { * conditioned_tokens = syn :: parse_quote ! { # conditioned_tokens else if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } } ; } else { conditioned_tokens = Some (syn :: parse_quote ! { if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } }) ; } } let conditioned_tokens : TokenStream = conditioned_tokens . unwrap () ; let id = id . splice () ; HfBuiltWithId { tokens : syn :: parse_quote ! ({ let __given_id = # id ; # conditioned_tokens else { panic ! ("Invalid node id: {}" , __given_id) ; } }) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfCompiled < 'a , () > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfCompiled < 'a , () > { fn to_tokens (mut self) -> (Option < TokenStream > , Option < TokenStream >) { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; if self . hydroflow_ir . len () != 1 { panic ! ("Expected exactly one subgraph in the Hydroflow IR") ; } let flat_graph = self . hydroflow_ir . remove (& 0) . unwrap () ; let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; (None , Some (tokens)) } } pub use crate :: HfBuiltWithId ; # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfBuiltWithId < 'a > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfBuiltWithId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (self . tokens)) } }
[INFO] [stdout]   |
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] error: `box` patterns have been removed (feature `box_patterns`)
[INFO] [stdout]  --> /opt/rustwide/target/debug/build/hydroflow_plus/5672655b657d1e44/out/lib_pub.rs:1:93383
[INFO] [stdout]   |
[INFO] [stdout] 1 | ...{ unreachable ! () } } HfPlusNode :: FlatMap { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: FlatMap...
[INFO] [stdout]   |                                                                   ^^^
[INFO] [stdout]   |
[INFO] [stdout]   = help: enable feature `deref_patterns` instead and...
[INFO] [stdout] help: ...if possible just remove keyword `box`...
[INFO] [stdout]   |
[INFO] [stdout] 1 - pub use std :: collections :: BTreeMap ; pub use std :: marker :: PhantomData ; pub use hydroflow :: scheduled :: context :: Context ; pub use hydroflow :: scheduled :: graph :: Hydroflow ; pub use hydroflow :: * ; pub use lang :: graph :: { partition_graph , HydroflowGraph } ; pub use proc_macro2 :: TokenStream ; pub use quote :: quote ; pub use stageleft :: runtime_support :: FreeVariable ; pub use stageleft :: Quoted ; pub mod runtime_support { pub use bincode ; } pub mod stream { pub use std :: cell :: RefCell ; pub use std :: hash :: Hash ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow :: bytes :: Bytes ; pub use hydroflow :: futures :: Sink ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: quote ; pub use serde :: de :: DeserializeOwned ; pub use serde :: Serialize ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use syn :: parse_quote ; pub use crate :: builder :: { ClusterIds , FlowLeaves } ; pub use crate :: cycle :: { CycleCollection , CycleComplete } ; pub use crate :: ir :: { DebugInstantiate , HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { CanSend , Location , LocationId } ; pub use crate :: { Cluster , Optional , Singleton } ; pub use crate :: stream :: Unbounded ; pub use crate :: stream :: Bounded ; pub use crate :: stream :: NoTick ; pub use crate :: stream :: Tick ; pub use crate :: stream :: Stream ; # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Stream { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Stream < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Stream { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , C , N > > ,) -> Stream < 'a , (T , O) , W , C , N > where O : Clone , { let other : Optional < 'a , O , Bounded , C , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn cross_product < O > (self , other : Stream < 'a , O , W , C , N >) -> Stream < 'a , (T , O) , W , C , N > where T : Clone , O : Clone , { if self . location_kind != other . location_kind { panic ! ("cross_product must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossProduct (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn union (self , other : Stream < 'a , T , W , C , N >) -> Stream < 'a , T , W , C , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn dest_sink < S : Unpin + Sink < T > + 'a > (self , sink : impl Quoted < 'a , S >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: DestSink { sink : sink . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn first (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } # [doc = " Allow this stream through if the other stream has elements, otherwise the output is empty."] pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } # [doc = " Allow this stream through if the other stream is empty, otherwise the output is empty."] pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn enumerate (self) -> Stream < 'a , (usize , T) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Enumerate (Box :: new (self . ir_node . into_inner ())) ,) } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn sort (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Ord , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Sort (Box :: new (self . ir_node . into_inner ())) ,) } pub fn count (self) -> Singleton < 'a , usize , Bounded , Tick , N > { self . fold (q ! (|| 0usize) , q ! (| count , _ | * count += 1)) } pub fn delta (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } pub fn unique (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Eq + Hash , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unique (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn tick_batch (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_prefix (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { self . tick_batch () . persist () } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn for_each < F : Fn (T) + 'a > (self , f : impl IntoQuotedMut < 'a , F >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: ForEach { input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , f : f . splice () . into () , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Unbounded , NoTick , N > { pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . tick_batch () . continue_if (samples . first ()) . all_ticks () } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Unbounded , NoTick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , C , N : Location > Stream < 'a , T , Bounded , C , N > { pub fn filter_not_in (self , other : Stream < 'a , T , Bounded , C , N >) -> Stream < 'a , T , Bounded , C , N > where T : Eq + Hash , { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Difference (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Stream < 'a , & T , W , C , N > { pub fn cloned (self) -> Stream < 'a , T , W , C , N > { self . map (q ! (| d | d . clone ())) } } # [cfg (stageleft_macro)] impl < 'a , K , V1 , W , C , N : Location > Stream < 'a , (K , V1) , W , C , N > { pub fn join < W2 , V2 > (self , n : Stream < 'a , (K , V2) , W2 , C , N > ,) -> Stream < 'a , (K , (V1 , V2)) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Join (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } pub fn anti_join < W2 > (self , n : Stream < 'a , K , W2 , C , N >) -> Stream < 'a , (K , V1) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("anti_join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: AntiJoin (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , K : Eq + Hash , V , N : Location > Stream < 'a , (K , V) , Bounded , Tick , N > { pub fn fold_keyed < A , I : Fn () -> A + 'a , F : Fn (& mut A , V) + 'a > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , A) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FoldKeyed { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce_keyed < F : Fn (& mut V , V) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , V) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: ReduceKeyed { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } pub fn get_this_crate () -> TokenStream { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , Span :: call_site ()) ; quote ! { # ident } } } } pub fn serialize_bincode < T : Serialize > (is_demux : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if is_demux { parse_quote ! { map (| (id , data) | { (id , # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into ()) }) } } else { parse_quote ! { map (| data | { # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into () }) } } } pub fn deserialize_bincode < T : DeserializeOwned > (tagged : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if tagged { parse_quote ! { map (| res | { let (id , b) = res . unwrap () ; (id , # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& b) . unwrap ()) }) } } else { parse_quote ! { map (| res | { # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& res . unwrap ()) . unwrap () }) } } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn send_bincode < N2 : Location , CoreType > (self , other : & N2 ,) -> Stream < 'a , N :: Out < CoreType > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T > , CoreType : Serialize + DeserializeOwned , { let serialize_pipeline = Some (serialize_bincode :: < CoreType > (N :: is_demux ())) ; let deserialize_pipeline = Some (deserialize_bincode :: < CoreType > (N :: is_tagged ())) ; Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bytes < N2 : Location > (self , other : & N2 ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T > , { Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline : None , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline : if N :: is_tagged () { Some (parse_quote ! (map (| (id , b) | (id , b . unwrap () . freeze ())))) } else { Some (parse_quote ! (map (| b | b . unwrap () . freeze ()))) } , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bincode_interleaved < N2 : Location , Tag , CoreType > (self , other : & N2 ,) -> Stream < 'a , CoreType , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T , Out < CoreType > = (Tag , CoreType) > , CoreType : Serialize + DeserializeOwned , { self . send_bincode :: < N2 , CoreType > (other) . map (q ! (| (_ , b) | b)) } pub fn send_bytes_interleaved < N2 : Location , Tag > (self , other : & N2 ,) -> Stream < 'a , Bytes , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T , Out < Bytes > = (Tag , Bytes) > , { self . send_bytes :: < N2 > (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bincode < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < T > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) > , T : Clone + Serialize + DeserializeOwned , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bincode (other) } pub fn broadcast_bincode_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , T , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) , Out < T > = (Tag , T) > + 'a , T : Clone + Serialize + DeserializeOwned , { self . broadcast_bincode (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bytes < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) > + 'a , T : Clone , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bytes (other) } pub fn broadcast_bytes_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , Bytes , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) , Out < Bytes > = (Tag , Bytes) > + 'a , T : Clone , { self . broadcast_bytes (other) . map (q ! (| (_ , b) | b)) } } } pub use stream :: { Bounded , NoTick , Stream , Tick , Unbounded } ; pub mod singleton { pub use std :: cell :: RefCell ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use crate :: builder :: FlowLeaves ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial , CycleComplete } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: Stream ; pub use crate :: singleton :: CrossResult ; # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Singleton < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Singleton :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } pub use crate :: singleton :: Singleton ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Singleton { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleComplete < 'a > for Singleton < 'a , T , Bounded , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleCollectionWithInitial < 'a > for Singleton < 'a , T , Bounded , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , initial : Self , l : LocationId ,) -> Self { Singleton :: new (l , ir_leaves , HfPlusNode :: Union (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , }) , initial . ir_node . into_inner () . into () ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Singleton < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Singleton { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , U , W , C , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (Self :: other_ir_node (other)) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Singleton < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CrossSingleton (Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , Box :: new (HfPlusNode :: Unpersist (Box :: new (Self :: other_ir_node (other)))) ,))) ,) } } pub use crate :: singleton :: Optional ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Optional { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } pub fn some (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: new (singleton . location_kind , singleton . ir_leaves , singleton . ir_node . into_inner () ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > From < Singleton < 'a , T , W , C , N > > for Optional < 'a , T , W , C , N > { fn from (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: some (singleton) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Optional < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Optional { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn into_stream (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , Tick , N > > ,) -> Optional < 'a , (T , O) , Bounded , Tick , N > where O : Clone , { let other : Optional < 'a , O , Bounded , Tick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn union (self , other : Optional < 'a , T , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Optional < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_samples (self) -> Stream < 'a , T , Unbounded , NoTick , N > { self . latest_tick () . all_ticks () } pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . latest_tick () . continue_if (samples . first ()) . latest () . tick_samples () } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Unbounded , NoTick , N > > ,) -> Optional < 'a , (T , O) , Unbounded , NoTick , N > where O : Clone , { let other : Optional < 'a , O , Unbounded , NoTick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } self . latest_tick () . cross_singleton (other . latest_tick ()) . latest () } } } pub use singleton :: { Optional , Singleton } ; pub mod location { pub use std :: marker :: PhantomData ; pub use crate :: location :: LocationId ; pub use crate :: location :: Location ; pub use crate :: location :: Process ; # [cfg (stageleft_macro)] impl < P > Clone for Process < P > { fn clone (& self) -> Self { Process { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < P > Location for Process < P > { fn id (& self) -> LocationId { LocationId :: Process (self . id) } } pub use crate :: location :: Cluster ; # [cfg (stageleft_macro)] impl < C > Clone for Cluster < C > { fn clone (& self) -> Self { Cluster { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < C > Location for Cluster < C > { fn id (& self) -> LocationId { LocationId :: Cluster (self . id) } } pub use crate :: location :: CanSend ; # [cfg (stageleft_macro)] impl < P1 , P2 > CanSend < Process < P2 > > for Process < P1 > { type In < T > = T ; type Out < T > = T ; fn is_demux () -> bool { false } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < P1 , C2 > CanSend < Cluster < C2 > > for Process < P1 > { type In < T > = (u32 , T) ; type Out < T > = T ; fn is_demux () -> bool { true } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < C1 , P2 > CanSend < Process < P2 > > for Cluster < C1 > { type In < T > = T ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { false } fn is_tagged () -> bool { true } } # [cfg (stageleft_macro)] impl < C1 , C2 > CanSend < Cluster < C2 > > for Cluster < C1 > { type In < T > = (u32 , T) ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { true } fn is_tagged () -> bool { true } } } pub use location :: { Cluster , Process } ; pub mod deploy { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use stageleft :: Quoted ; pub mod graphs { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use super :: { LocalDeploy , Node , ProcessSpec } ; pub use crate :: deploy :: graphs :: SingleProcessGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for SingleProcessGraph { type Process = SingleNode ; type Cluster = SingleNode ; type Meta = () ; type GraphId = () ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { SingleNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { SingleNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , SingleProcessGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> SingleNode { SingleNode { } } } pub use crate :: deploy :: graphs :: SingleNode ; # [cfg (stageleft_macro)] impl Node for SingleNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } pub use crate :: deploy :: graphs :: MultiGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for MultiGraph { type Process = MultiNode ; type Cluster = MultiNode ; type Meta = () ; type GraphId = usize ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { MultiNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { MultiNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , MultiGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> MultiNode { MultiNode { } } } pub use crate :: deploy :: graphs :: MultiNode ; # [cfg (stageleft_macro)] impl Node for MultiNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } } pub use graphs :: * ; pub use crate :: deploy :: LocalDeploy ; pub use crate :: deploy :: Deploy ; # [cfg (stageleft_macro)] impl < 'a , T : Deploy < 'a , Process = N , Cluster = C , Meta = M , GraphId = R > , N : Node < Meta = M > , C : Node < Meta = M > , M : Default , R , > LocalDeploy < 'a > for T { type Process = N ; type Cluster = C ; type Meta = M ; type GraphId = R ; fn has_trivial_node () -> bool { < T as Deploy < 'a > > :: has_trivial_node () } fn trivial_process (id : usize) -> Self :: Process { < T as Deploy < 'a > > :: trivial_process (id) } fn trivial_cluster (id : usize) -> Self :: Cluster { < T as Deploy < 'a > > :: trivail_cluster (id) } } pub use crate :: deploy :: ProcessSpec ; pub use crate :: deploy :: ClusterSpec ; pub use crate :: deploy :: Node ; } pub use deploy :: { ClusterSpec , Deploy , ProcessSpec } ; pub mod cycle { pub use std :: marker :: PhantomData ; pub use crate :: builder :: FlowLeaves ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: cycle :: CycleComplete ; pub use crate :: cycle :: CycleCollection ; pub use crate :: cycle :: CycleCollectionWithInitial ; pub use crate :: cycle :: HfCycle ; # [cfg (stageleft_macro)] impl < 'a , S : CycleComplete < 'a > > HfCycle < 'a , S > { pub fn complete (self , stream : S) { let ident = self . ident ; S :: complete (stream , ident) } } } pub use cycle :: HfCycle ; pub mod builder { pub use std :: cell :: RefCell ; pub use std :: collections :: HashMap ; pub use std :: marker :: PhantomData ; pub use std :: rc :: Rc ; pub use std :: time :: Duration ; pub use hydroflow :: futures :: stream :: Stream as FuturesStream ; pub use hydroflow :: { tokio , tokio_stream } ; pub use internal :: TokenStream ; pub use proc_macro2 :: Span ; pub use quote :: quote ; pub use runtime_support :: FreeVariable ; pub use stageleft :: * ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Cluster , Location , LocationId , Process } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: { HfCycle , Optional , RuntimeContext , Singleton , Stream } ; pub mod built { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use hydroflow_lang :: graph :: { eliminate_extra_unions_tees , HydroflowGraph } ; pub use super :: deploy :: { DeployFlow , DeployResult } ; pub use crate :: deploy :: { ClusterSpec , Deploy , LocalDeploy , ProcessSpec } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Cluster , Process } ; pub use crate :: HfCompiled ; pub use crate :: builder :: built :: BuiltFlow ; # [cfg (stageleft_macro)] impl < 'a > Drop for BuiltFlow < 'a > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped BuiltFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn ir (& self) -> & Vec < HfPlusLeaf < 'a > > { & self . ir } pub fn optimize_with (mut self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> BuiltFlow < 'a > { self . used = true ; BuiltFlow { ir : f (std :: mem :: take (& mut self . ir)) , processes : std :: mem :: take (& mut self . processes) , clusters : std :: mem :: take (& mut self . clusters) , used : false , _phantom : PhantomData , } } } pub fn build_inner (ir : & mut Vec < HfPlusLeaf >) -> BTreeMap < usize , HydroflowGraph > { let mut builders = BTreeMap :: new () ; let mut built_tees = HashMap :: new () ; let mut next_stmt_id = 0 ; for leaf in ir { leaf . emit (& mut builders , & mut built_tees , & mut next_stmt_id) ; } builders . into_iter () . map (| (k , v) | { let (mut flat_graph , _ , _) = v . build () ; eliminate_extra_unions_tees (& mut flat_graph) ; (k , flat_graph) }) . collect () } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn compile_no_network < D : LocalDeploy < 'a > > (mut self) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; HfCompiled { hydroflow_ir : build_inner (& mut self . ir) , extra_stmts : BTreeMap :: new () , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> BuiltFlow < 'a > { self . optimize_with (crate :: persist_pullup :: persist_pullup) } fn into_deploy < D : LocalDeploy < 'a > > (mut self) -> DeployFlow < 'a , D > { self . used = true ; let processes = if D :: has_trivial_node () { self . processes . iter () . map (| id | (* id , D :: trivial_process (* id))) . collect () } else { HashMap :: new () } ; let clusters = if D :: has_trivial_node () { self . clusters . iter () . map (| id | (* id , D :: trivial_cluster (* id))) . collect () } else { HashMap :: new () } ; DeployFlow { ir : std :: mem :: take (& mut self . ir) , nodes : processes , clusters , used : false , _phantom : PhantomData , } } pub fn with_process < P , D : LocalDeploy < 'a > > (self , process : & Process < P > , spec : impl ProcessSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_process (process , spec) } pub fn with_cluster < C , D : LocalDeploy < 'a > > (self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_cluster (cluster , spec) } pub fn compile < D : Deploy < 'a > + 'a > (self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . into_deploy :: < D > () . compile (env) } pub fn deploy < D : Deploy < 'a , CompileEnv = () > + 'a > (self , env : & mut D :: InstantiateEnv ,) -> DeployResult < 'a , D > { self . into_deploy :: < D > () . deploy (env) } } } pub mod deploy { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use proc_macro2 :: Span ; pub use stageleft :: Quoted ; pub use super :: built :: build_inner ; pub use crate :: deploy :: { LocalDeploy , Node } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: { Cluster , ClusterSpec , Deploy , HfCompiled , Process , ProcessSpec } ; pub use crate :: builder :: deploy :: DeployFlow ; # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > Drop for DeployFlow < 'a , D > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped DeployFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > DeployFlow < 'a , D > { pub fn with_process < P > (mut self , process : & Process < P > , spec : impl ProcessSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < P > () . to_string () ; self . nodes . insert (process . id , spec . build (process . id , & tag_name)) ; self } pub fn with_cluster < C > (mut self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < C > () . to_string () ; self . clusters . insert (cluster . id , spec . build (cluster . id , & tag_name)) ; self } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployFlow < 'a , D > { pub fn compile (mut self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; let mut seen_tees : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | leaf . compile_network :: < D > (env , & mut seen_tees , & self . nodes , & self . clusters)) . collect () ; let extra_stmts = self . extra_stmts (env) ; HfCompiled { hydroflow_ir : build_inner (& mut ir_leaves_networked) , extra_stmts , _phantom : PhantomData , } } fn extra_stmts (& self , env : & < D as Deploy < 'a > > :: CompileEnv) -> BTreeMap < usize , Vec < syn :: Stmt > > { let all_locations_count = self . nodes . len () + self . clusters . len () ; let mut extra_stmts : BTreeMap < usize , Vec < syn :: Stmt > > = BTreeMap :: new () ; for & c_id in self . clusters . keys () { let self_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , c_id) , Span :: call_site () ,) ; let self_id_expr = D :: cluster_self_id (env) . splice () ; extra_stmts . entry (c_id) . or_default () . push (syn :: parse_quote ! { let # self_id_ident = # self_id_expr ; }) ; for other_location in 0 .. all_locations_count { let other_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , c_id) , Span :: call_site () ,) ; let other_id_expr = D :: cluster_ids (env , c_id) . splice () ; extra_stmts . entry (other_location) . or_default () . push (syn :: parse_quote ! { let # other_id_ident = # other_id_expr ; }) ; } } extra_stmts } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a , CompileEnv = () > > DeployFlow < 'a , D > { # [must_use] pub fn deploy (mut self , env : & mut D :: InstantiateEnv) -> DeployResult < 'a , D > { self . used = true ; let mut seen_tees_instantiate : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | { leaf . compile_network :: < D > (& () , & mut seen_tees_instantiate , & self . nodes , & self . clusters ,) }) . collect () ; let mut compiled = build_inner (& mut ir_leaves_networked) ; let mut extra_stmts = self . extra_stmts (& ()) ; let mut meta = D :: Meta :: default () ; let (mut processes , mut clusters) = (std :: mem :: take (& mut self . nodes) . into_iter () . map (| (node_id , node) | { node . instantiate (env , & mut meta , compiled . remove (& node_id) . unwrap () , extra_stmts . remove (& node_id) . unwrap_or_default () ,) ; (node_id , node) }) . collect :: < HashMap < _ , _ > > () , std :: mem :: take (& mut self . clusters) . into_iter () . map (| (cluster_id , cluster) | { cluster . instantiate (env , & mut meta , compiled . remove (& cluster_id) . unwrap () , extra_stmts . remove (& cluster_id) . unwrap_or_default () ,) ; (cluster_id , cluster) }) . collect :: < HashMap < _ , _ > > () ,) ; for node in processes . values_mut () { node . update_meta (& meta) ; } for cluster in clusters . values_mut () { cluster . update_meta (& meta) ; } let mut seen_tees_connect = HashMap :: new () ; for leaf in ir_leaves_networked { leaf . connect_network (& mut seen_tees_connect) ; } DeployResult { processes , clusters , } } } pub use crate :: builder :: deploy :: DeployResult ; # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployResult < 'a , D > { pub fn get_process < P > (& self , p : & Process < P >) -> & D :: Process { let id = match p . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . processes . get (& id) . unwrap () } pub fn get_cluster < C > (& self , c : & Cluster < C >) -> & D :: Cluster { let id = match c . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . clusters . get (& id) . unwrap () } } } # [doc = " Tracks the leaves of the dataflow IR. This is referenced by"] # [doc = " `Stream` and `HfCycle` to build the IR. The inner option will"] # [doc = " be set to `None` when this builder is finalized."] pub type FlowLeaves < 'a > = Rc < RefCell < Option < Vec < HfPlusLeaf < 'a > > > > > ; pub use crate :: builder :: ClusterIds ; # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Vec < u32 > > for ClusterIds < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , & 'a Vec < u32 > > for ClusterIds < 'a > { } # [derive (Copy , Clone)] pub struct ClusterSelfId < 'a > { pub id : usize , pub _phantom : PhantomData < & 'a mut & 'a u32 > , } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < u32 > for ClusterSelfId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , u32 > for ClusterSelfId < 'a > { } pub use crate :: builder :: FlowBuilder ; # [cfg (stageleft_macro)] impl < 'a > Drop for FlowBuilder < 'a > { fn drop (& mut self) { if ! self . finalized { panic ! ("Dropped FlowBuilder without finalizing, you may have forgotten to call `with_default_optimize`, `optimize_with`, or `finalize`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > QuotedContext for FlowBuilder < 'a > { fn create () -> Self { FlowBuilder :: new () } } # [cfg (stageleft_macro)] impl < 'a > FlowBuilder < 'a > { # [allow (clippy :: new_without_default)] pub fn new () -> FlowBuilder < 'a > { FlowBuilder { ir_leaves : Rc :: new (RefCell :: new (Some (Vec :: new ()))) , nodes : RefCell :: new (vec ! []) , clusters : RefCell :: new (vec ! []) , cycle_ids : RefCell :: new (HashMap :: new ()) , next_node_id : RefCell :: new (0) , finalized : false , _phantom : PhantomData , } } pub fn finalize (mut self) -> built :: BuiltFlow < 'a > { self . finalized = true ; built :: BuiltFlow { ir : self . ir_leaves . borrow_mut () . take () . unwrap () , processes : self . nodes . replace (vec ! []) , clusters : self . clusters . replace (vec ! []) , used : false , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> built :: BuiltFlow < 'a > { self . finalize () . with_default_optimize () } pub fn optimize_with (self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> built :: BuiltFlow < 'a > { self . finalize () . optimize_with (f) } pub fn ir_leaves (& self) -> & FlowLeaves < 'a > { & self . ir_leaves } pub fn process < P > (& self) -> Process < P > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . nodes . borrow_mut () . push (id) ; Process { id , _phantom : PhantomData , } } pub fn cluster < C > (& self) -> Cluster < C > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . clusters . borrow_mut () . push (id) ; Cluster { id , _phantom : PhantomData , } } pub fn runtime_context (& self) -> RuntimeContext < 'a > { RuntimeContext { _phantom : PhantomData , } } pub fn cluster_members < C > (& self , cluster : & Cluster < C > ,) -> impl Quoted < 'a , & 'a Vec < u32 > > + Copy + 'a { ClusterIds { id : cluster . id , _phantom : PhantomData , } } pub fn cluster_self_id < C > (& self , cluster : & Cluster < C >) -> impl Quoted < 'a , u32 > + Copy + 'a { ClusterSelfId { id : cluster . id , _phantom : PhantomData , } } pub fn spin < L : Location > (& self , on : & L) -> Stream < 'a , () , Unbounded , NoTick , L > { Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Spin () , location_kind : on . id () , })) ,) } pub fn spin_batch < L : Location > (& self , on : & L , batch_size : impl Quoted < 'a , usize > + Copy + 'a ,) -> Stream < 'a , () , Bounded , Tick , L > { self . spin (on) . flat_map (q ! (move | _ | 0 .. batch_size)) . map (q ! (| _ | ())) . tick_batch () } pub fn source_stream < T , E : FuturesStream < Item = T > + Unpin , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Unbounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Stream (e . into ()) , location_kind : on . id () , })) ,) } pub fn source_iter < T , E : IntoIterator < Item = T > , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Bounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , })) ,) } pub fn singleton < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Singleton < 'a , T , Bounded , NoTick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Singleton :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,)))) ,) } pub fn singleton_first_tick < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Optional < 'a , T , Bounded , Tick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,) } pub fn source_interval < L : Location > (& self , on : & L , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , () , Unbounded , NoTick , L > { let interval = interval . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : on . id () , })) ,) } pub fn source_interval_delayed < L : Location > (& self , on : & L , delay : impl Quoted < 'a , Duration > + Copy + 'a , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , tokio :: time :: Instant , Unbounded , NoTick , L > { self . source_stream (on , q ! (tokio_stream :: wrappers :: IntervalStream :: new (tokio :: time :: interval_at (tokio :: time :: Instant :: now () + delay , interval))) ,) . tick_batch () . first () . latest () } pub fn cycle < S : CycleCollection < 'a > > (& self , on : & S :: Location) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , on . id ()) ,) } pub fn cycle_with_initial < S : CycleCollectionWithInitial < 'a > > (& self , on : & S :: Location , initial : S ,) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , initial , on . id ()) ,) } } } pub use builder :: FlowBuilder ; pub mod ir { pub use core :: panic ; pub use std :: cell :: RefCell ; pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow_lang :: graph :: FlatGraphBuilder ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: ToTokens ; pub use syn :: parse_quote ; pub use crate :: deploy :: Deploy ; pub use crate :: location :: LocationId ; pub use crate :: ir :: DebugExpr ; # [cfg (stageleft_macro)] impl From < syn :: Expr > for DebugExpr { fn from (expr : syn :: Expr) -> DebugExpr { DebugExpr (expr) } } # [cfg (stageleft_macro)] impl Deref for DebugExpr { type Target = syn :: Expr ; fn deref (& self) -> & Self :: Target { & self . 0 } } # [cfg (stageleft_macro)] impl ToTokens for DebugExpr { fn to_tokens (& self , tokens : & mut TokenStream) { self . 0 . to_tokens (tokens) ; } } # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugExpr { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "{}" , self . 0 . to_token_stream ()) } } pub use crate :: ir :: DebugInstantiate ; # [cfg (stageleft_macro)] impl < 'a > std :: fmt :: Debug for DebugInstantiate < 'a > { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<network instantiate>") } } pub use crate :: ir :: DebugPipelineFn ; # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugPipelineFn { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<function>") } } pub use crate :: ir :: HfPlusSource ; pub use crate :: ir :: HfPlusLeaf ; # [cfg (stageleft_macro)] impl < 'a > HfPlusLeaf < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . compile_network :: < D > (compile_env , s , nodes , clusters) ; } , seen_tees ,) } pub fn connect_network (self , seen_tees : & mut SeenTees < 'a >) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . connect_network (s) ; } , seen_tees ,) } pub fn transform_children (self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) -> HfPlusLeaf < 'a > { match self { HfPlusLeaf :: ForEach { f , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: ForEach { f , input } } HfPlusLeaf :: DestSink { sink , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: DestSink { sink , input } } HfPlusLeaf :: CycleSink { ident , location_kind , mut input , } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: CycleSink { ident , location_kind , input , } } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) { match self { HfPlusLeaf :: ForEach { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> for_each (# f) ; }) ; } HfPlusLeaf :: DestSink { sink , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink) ; }) ; } HfPlusLeaf :: CycleSink { ident , location_kind , input , } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; assert_eq ! (input_location_id , * location_id , "cycle_sink location mismatch") ; graph_builders . entry (* location_id) . or_default () . add_statement (parse_quote ! { # ident = # input_ident ; }) ; } } } } pub use crate :: ir :: HfPlusNode ; pub type SeenTees < 'a > = HashMap < * const RefCell < HfPlusNode < 'a > > , Rc < RefCell < HfPlusNode < 'a > > > > ; # [cfg (stageleft_macro)] impl < 'a > HfPlusNode < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (& mut self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) { self . transform_children (| n , s | n . compile_network :: < D > (compile_env , s , nodes , clusters) , seen_tees ,) ; if let HfPlusNode :: Network { from_location , to_location , instantiate_fn , .. } = self { let (sink_expr , source_expr , connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { let ((sink , source) , connect_fn) = match (from_location , to_location) { (LocationId :: Process (from) , LocationId :: Process (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: o2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Process (from) , LocationId :: Cluster (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: o2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Process (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: m2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Cluster (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: m2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } } ; (sink , source , connect_fn) } DebugInstantiate :: Finalized (_ , _ , _) => panic ! ("network already finalized") , } ; * instantiate_fn = DebugInstantiate :: Finalized (sink_expr , source_expr , connect_fn) ; } } pub fn connect_network (& mut self , seen_tees : & mut SeenTees < 'a >) { self . transform_children (| n , s | n . connect_network (s) , seen_tees) ; if let HfPlusNode :: Network { instantiate_fn , .. } = self { match instantiate_fn { DebugInstantiate :: Building () => panic ! ("network not built") , DebugInstantiate :: Finalized (_ , _ , ref connect_fn) => { connect_fn () ; } } } } pub fn transform_children (& mut self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) { match self { HfPlusNode :: Placeholder => { panic ! () ; } HfPlusNode :: Source { .. } => { } HfPlusNode :: CycleSource { .. } => { } HfPlusNode :: Tee { inner } => { if let Some (transformed) = seen_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { * inner = transformed . clone () ; } else { let transformed_cell = Rc :: new (RefCell :: new (HfPlusNode :: Placeholder)) ; seen_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , transformed_cell . clone () ,) ; let mut orig = inner . replace (HfPlusNode :: Placeholder) ; transform (& mut orig , seen_tees) ; * transformed_cell . borrow_mut () = orig ; * inner = transformed_cell ; } } HfPlusNode :: Persist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Unpersist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Delta (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Union (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossProduct (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossSingleton (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Join (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Difference (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: AntiJoin (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Map { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FlatMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Filter { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FilterMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Sort (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: DeferTick (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Enumerate (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Inspect { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Unique (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Fold { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FoldKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Reduce { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: ReduceKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Network { input , .. } => { transform (input . as_mut () , seen_tees) ; } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) -> (syn :: Ident , usize) { match self { HfPlusNode :: Placeholder => { panic ! () } HfPlusNode :: Persist (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let persist_id = * next_stmt_id ; * next_stmt_id += 1 ; let persist_ident = syn :: Ident :: new (& format ! ("stream_{}" , persist_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # persist_ident = # inner_ident -> persist ::<'static > () ; }) ; (persist_ident , location) } HfPlusNode :: Unpersist (_) => { panic ! ("Unpersist is a marker node and should have been optimized away. This is likely a compiler bug.") } HfPlusNode :: Delta (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let delta_id = * next_stmt_id ; * next_stmt_id += 1 ; let delta_ident = syn :: Ident :: new (& format ! ("stream_{}" , delta_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # delta_ident = # inner_ident -> multiset_delta () ; }) ; (delta_ident , location) } HfPlusNode :: Source { source , location_kind , } => { let source_id = * next_stmt_id ; * next_stmt_id += 1 ; let source_ident = syn :: Ident :: new (& format ! ("stream_{}" , source_id) , Span :: call_site ()) ; let source_stmt = match source { HfPlusSource :: Stream (expr) => { parse_quote ! { # source_ident = source_stream (# expr) ; } } HfPlusSource :: Iter (expr) => { parse_quote ! { # source_ident = source_iter (# expr) ; } } HfPlusSource :: Interval (expr) => { parse_quote ! { # source_ident = source_interval (# expr) ; } } HfPlusSource :: Spin () => { parse_quote ! { # source_ident = spin () ; } } } ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; graph_builders . entry (* location_id) . or_default () . add_statement (source_stmt) ; (source_ident , * location_id) } HfPlusNode :: CycleSource { ident , location_kind , } => { let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; (ident . clone () , * location_id) } HfPlusNode :: Tee { inner } => { if let Some (ret) = built_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { ret . clone () } else { let (inner_ident , inner_location_id) = inner . borrow () . emit (graph_builders , built_tees , next_stmt_id) ; let tee_id = * next_stmt_id ; * next_stmt_id += 1 ; let tee_ident = syn :: Ident :: new (& format ! ("stream_{}" , tee_id) , Span :: call_site ()) ; let builder = graph_builders . entry (inner_location_id) . or_default () ; builder . add_statement (parse_quote ! { # tee_ident = # inner_ident -> tee () ; }) ; built_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , (tee_ident . clone () , inner_location_id) ,) ; (tee_ident , inner_location_id) } } HfPlusNode :: Union (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "union inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let union_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # union_ident = union () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [0] # union_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # union_ident ; }) ; (union_ident , left_location_id) } HfPlusNode :: CrossSingleton (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "cross_singleton inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let cross_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # cross_ident = cross_singleton () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [input] # cross_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [single] # cross_ident ; }) ; (cross_ident , left_location_id) } HfPlusNode :: CrossProduct (..) | HfPlusNode :: Join (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: CrossProduct (..)) { parse_quote ! (cross_join_multiset) } else { parse_quote ! (join_multiset) } ; let (HfPlusNode :: CrossProduct (left , right) | HfPlusNode :: Join (left , right)) = self else { unreachable ! () } ; let (left_inner , left_was_persist) = if let HfPlusNode :: Persist (left) = left . as_ref () { (left , true) } else { (left , false) } ; let (right_inner , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left_inner . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right_inner . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "join / cross product inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; match (left_was_persist , right_was_persist) { (true , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'static > () ; }) ; } (true , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'tick > () ; }) ; } (false , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } (false , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } } ; builder . add_statement (parse_quote ! { # left_ident -> [0] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Difference (..) | HfPlusNode :: AntiJoin (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Difference (..)) { parse_quote ! (difference_multiset) } else { parse_quote ! (anti_join_multiset) } ; let (HfPlusNode :: Difference (left , right) | HfPlusNode :: AntiJoin (left , right)) = self else { unreachable ! () } ; let (right , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "difference / anti join inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; if right_was_persist { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } else { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } builder . add_statement (parse_quote ! { # left_ident -> [pos] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [neg] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Map { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let map_id = * next_stmt_id ; * next_stmt_id += 1 ; let map_ident = syn :: Ident :: new (& format ! ("stream_{}" , map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # map_ident = # input_ident -> map (# f) ; }) ; (map_ident , input_location_id) } HfPlusNode :: FlatMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let flat_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let flat_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , flat_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # flat_map_ident = # input_ident -> flat_map (# f) ; }) ; (flat_map_ident , input_location_id) } HfPlusNode :: Filter { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_ident = # input_ident -> filter (# f) ; }) ; (filter_ident , input_location_id) } HfPlusNode :: FilterMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_map_ident = # input_ident -> filter_map (# f) ; }) ; (filter_map_ident , input_location_id) } HfPlusNode :: Sort (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sort_id = * next_stmt_id ; * next_stmt_id += 1 ; let sort_ident = syn :: Ident :: new (& format ! ("stream_{}" , sort_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # sort_ident = # input_ident -> sort () ; }) ; (sort_ident , input_location_id) } HfPlusNode :: DeferTick (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let defer_tick_id = * next_stmt_id ; * next_stmt_id += 1 ; let defer_tick_ident = syn :: Ident :: new (& format ! ("stream_{}" , defer_tick_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # defer_tick_ident = # input_ident -> defer_tick_lazy () ; }) ; (defer_tick_ident , input_location_id) } HfPlusNode :: Enumerate (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let enumerate_id = * next_stmt_id ; * next_stmt_id += 1 ; let enumerate_ident = syn :: Ident :: new (& format ! ("stream_{}" , enumerate_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # enumerate_ident = # input_ident -> enumerate () ; }) ; (enumerate_ident , input_location_id) } HfPlusNode :: Inspect { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let inspect_id = * next_stmt_id ; * next_stmt_id += 1 ; let inspect_ident = syn :: Ident :: new (& format ! ("stream_{}" , inspect_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # inspect_ident = # input_ident -> inspect (# f) ; }) ; (inspect_ident , input_location_id) } HfPlusNode :: Unique (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let unique_id = * next_stmt_id ; * next_stmt_id += 1 ; let unique_ident = syn :: Ident :: new (& format ! ("stream_{}" , unique_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # unique_ident = # input_ident -> unique ::<'tick > () ; }) ; (unique_ident , input_location_id) } HfPlusNode :: Fold { .. } | HfPlusNode :: FoldKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Fold { .. }) { parse_quote ! (fold) } else { parse_quote ! (fold_keyed) } ; let (HfPlusNode :: Fold { init , acc , input } | HfPlusNode :: FoldKeyed { init , acc , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let fold_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'static > (# init , # acc) ; }) ; } else { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'tick > (# init , # acc) ; }) ; } (fold_ident , input_location_id) } HfPlusNode :: Reduce { .. } | HfPlusNode :: ReduceKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Reduce { .. }) { parse_quote ! (reduce) } else { parse_quote ! (reduce_keyed) } ; let (HfPlusNode :: Reduce { f , input } | HfPlusNode :: ReduceKeyed { f , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let reduce_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'static > (# f) ; }) ; } else { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'tick > (# f) ; }) ; } (reduce_ident , input_location_id) } HfPlusNode :: Network { from_location : _ , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input , } => { let (sink_expr , source_expr , _connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { panic ! ("Expected the network to be finalized") } DebugInstantiate :: Finalized (sink , source , connect_fn) => { (sink , source , connect_fn) } } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sender_builder = graph_builders . entry (input_location_id) . or_default () ; if let Some (serialize_pipeline) = serialize_pipeline { sender_builder . add_statement (parse_quote ! { # input_ident -> # serialize_pipeline -> dest_sink (# sink_expr) ; }) ; } else { sender_builder . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink_expr) ; }) ; } let to_id = match to_location { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let receiver_builder = graph_builders . entry (* to_id) . or_default () ; let receiver_stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let receiver_stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , receiver_stream_id) , Span :: call_site ()) ; if let Some (deserialize_pipeline) = deserialize_pipeline { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) -> # deserialize_pipeline ; }) ; } else { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) ; }) ; } (receiver_stream_ident , * to_id) } } } } } pub mod persist_pullup { pub use std :: cell :: RefCell ; pub use std :: collections :: HashSet ; pub use std :: ops :: Deref ; pub use crate :: ir :: * ; pub fn persist_pullup_node < 'a > (node : & mut HfPlusNode < 'a > , seen_tees : & mut SeenTees < 'a > , persist_pulled_tees : & mut HashSet < * const RefCell < HfPlusNode < 'a > > > ,) { node . transform_children (| n , s | persist_pullup_node (n , s , persist_pulled_tees) , seen_tees ,) ; match node { HfPlusNode :: Unpersist (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Unpersist (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Delta (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Delta (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Tee { inner } => { if persist_pulled_tees . contains (& (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >)) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } else { let inner_borrow = inner . borrow () ; if let HfPlusNode :: Persist (_) = inner_borrow . deref () { drop (inner_borrow) ; persist_pulled_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >) ; if let HfPlusNode :: Persist (box behind_persist) = inner . replace (HfPlusNode :: Placeholder) { * inner . borrow_mut () = behind_persist ; } else { unreachable ! () } * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } } } HfPlusNode :: Map { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Map { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Map { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: FlatMap { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: FlatMap { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: FlatMap { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Filter { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Filter { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Filter { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Network { input : box HfPlusNode :: Persist (_) , .. } => { if let HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Union (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Union (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Union (left , right))) ; } else { unreachable ! () } } HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: CrossProduct (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,) ,)))) ; } else { unreachable ! () } } HfPlusNode :: Join (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Join (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: Join (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,))))) ; } else { unreachable ! () } } _ => { } } } pub fn persist_pullup (ir : Vec < HfPlusLeaf >) -> Vec < HfPlusLeaf > { let mut seen_tees = Default :: default () ; let mut persist_pulled_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| n , s | persist_pullup_node (n , s , & mut persist_pulled_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn persist_pullup_through_map () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } # [test] fn persist_pullup_behind_tee () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; let before_tee = flow . source_iter (& process , q ! (0 .. 10)) . tick_batch () . persist () ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } } } pub mod profiler { pub use std :: cell :: RefCell ; pub use hydroflow :: futures :: channel :: mpsc :: UnboundedSender ; pub use stageleft :: * ; pub use crate as hydroflow_plus ; pub use crate :: ir :: * ; pub use crate :: RuntimeContext ; pub fn increment_counter (count : & mut u64) { * count += 1 ; } pub fn quoted_any_fn < 'a , F : Fn (& usize) + 'a , Q : IntoQuotedMut < 'a , F > > (q : Q) -> Q { q } # [doc = " Add a profiling node before each node to count the cardinality of its input"] pub fn add_profiling_node < 'a > (node : & mut HfPlusNode < 'a > , _context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > , id : & mut u32 , seen_tees : & mut SeenTees < 'a > ,) { let my_id = * id ; * id += 1 ; node . transform_children (| node , seen_tees | { add_profiling_node (node , _context , counters , counter_queue , id , seen_tees) } , seen_tees ,) ; let orig_node = std :: mem :: replace (node , HfPlusNode :: Placeholder) ; * node = HfPlusNode :: Inspect { f : quoted_any_fn (q ! ({ counter_queue . borrow () . unbounded_send ((my_id as usize , counters . borrow () [my_id as usize])) . unwrap () ; counters . borrow_mut () [my_id as usize] = 0 ; move | _ | { hydroflow_plus :: profiler :: increment_counter (& mut counters . borrow_mut () [my_id as usize] ,) ; } })) . splice () . into () , input : Box :: new (orig_node) , } } # [doc = " Count the cardinality of each input and periodically output to a file"] pub fn profiling < 'a > (ir : Vec < HfPlusLeaf < 'a > > , context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > ,) -> Vec < HfPlusLeaf < 'a > > { let mut id = 0 ; let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | { add_profiling_node (node , context , counters , counter_queue , & mut id , seen_tees) } , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn profiler_wrapping_all_operators () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let runtime_context = flow . runtime_context () ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (& built . ir ()) ; let counters = RuntimeData :: new ("Fake") ; let counter_queue = RuntimeData :: new ("Fake") ; let pushed_down = built . with_default_optimize () . optimize_with (| ir | super :: profiling (ir , runtime_context , counters , counter_queue)) ; insta :: assert_debug_snapshot ! (& pushed_down . ir ()) ; let _ = pushed_down . compile_no_network :: < MultiGraph > () ; } } } pub mod properties { pub use std :: collections :: HashSet ; pub use stageleft :: * ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , SeenTees } ; pub use crate :: properties :: PropertyDatabase ; # [doc = " Allows us to convert the hydroflow datatype for folds to a binary operation for the algebra"] # [doc = " property tests."] # [allow (dead_code)] pub fn convert_hf_to_binary < I , A : Default , F : Fn (& mut A , I) > (f : F) -> impl Fn (I , I) -> A { move | a , b | { let mut acc = Default :: default () ; f (& mut acc , a) ; f (& mut acc , b) ; acc } } # [cfg (stageleft_macro)] impl PropertyDatabase { # [doc = " Tags the expression as commutative."] pub fn add_commutative_tag < 'a , I , A , F : Fn (& mut A , I) , Q : Quoted < 'a , F > + Clone > (& mut self , expr : Q ,) -> Q { let expr_clone = expr . clone () ; self . commutative . insert (expr_clone . splice ()) ; expr } pub fn is_tagged_commutative (& self , expr : & syn :: Expr) -> bool { self . commutative . contains (expr) } } pub fn properties_optimize_node < 'a > (node : & mut HfPlusNode < 'a > , db : & PropertyDatabase , seen_tees : & mut SeenTees < 'a > ,) { node . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , seen_tees ,) ; match node { HfPlusNode :: ReduceKeyed { f , .. } if db . is_tagged_commutative (& f . 0) => { dbg ! ("IDENTIFIED COMMUTATIVE OPTIMIZATION for {:?}" , & f) ; } _ => { } } } pub fn properties_optimize < 'a > (ir : Vec < HfPlusLeaf < 'a > > , db : & PropertyDatabase ,) -> Vec < HfPlusLeaf < 'a > > { let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use super :: * ; use crate :: deploy :: SingleProcessGraph ; use crate :: FlowBuilder ; # [test] fn test_property_database () { let mut db = PropertyDatabase :: default () ; assert ! (! db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; let _ = db . add_commutative_tag (q ! (| a : & mut i32 , b : i32 | * a += b)) ; assert ! (db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; } # [test] fn test_property_optimized () { let flow = FlowBuilder :: new () ; let mut database = PropertyDatabase :: default () ; let process = flow . process :: < () > () ; let counter_func = q ! (| count : & mut i32 , _ | * count += 1) ; let _ = database . add_commutative_tag (counter_func) ; flow . source_iter (& process , q ! (vec ! [])) . map (q ! (| string : String | (string , ()))) . tick_batch () . fold_keyed (q ! (|| 0) , counter_func) . all_ticks () . for_each (q ! (| (string , count) | println ! ("{}: {}" , string , count))) ; let built = flow . finalize () . optimize_with (| ir | properties_optimize (ir , & database)) . with_default_optimize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let _ = built . compile_no_network :: < SingleProcessGraph > () ; } } } pub use crate :: RuntimeContext ; # [cfg (stageleft_macro)] impl Copy for RuntimeContext < '_ > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Context > for RuntimeContext < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (quote ! (& context))) } } pub use crate :: HfCompiled ; # [cfg (stageleft_macro)] impl < 'a , ID > HfCompiled < 'a , ID > { pub fn hydroflow_ir (& self) -> & BTreeMap < usize , HydroflowGraph > { & self . hydroflow_ir } } # [cfg (stageleft_macro)] impl < 'a > HfCompiled < 'a , usize > { pub fn with_dynamic_id (self , id : impl Quoted < 'a , usize >) -> HfBuiltWithId < 'a > { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; let mut conditioned_tokens = None ; for (subgraph_id , flat_graph) in self . hydroflow_ir { let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; let my_extra_stmts = self . extra_stmts . get (& subgraph_id) . cloned () . unwrap_or_default () ; if let Some (conditioned_tokens) = conditioned_tokens . as_mut () { * conditioned_tokens = syn :: parse_quote ! { # conditioned_tokens else if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } } ; } else { conditioned_tokens = Some (syn :: parse_quote ! { if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } }) ; } } let conditioned_tokens : TokenStream = conditioned_tokens . unwrap () ; let id = id . splice () ; HfBuiltWithId { tokens : syn :: parse_quote ! ({ let __given_id = # id ; # conditioned_tokens else { panic ! ("Invalid node id: {}" , __given_id) ; } }) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfCompiled < 'a , () > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfCompiled < 'a , () > { fn to_tokens (mut self) -> (Option < TokenStream > , Option < TokenStream >) { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; if self . hydroflow_ir . len () != 1 { panic ! ("Expected exactly one subgraph in the Hydroflow IR") ; } let flat_graph = self . hydroflow_ir . remove (& 0) . unwrap () ; let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; (None , Some (tokens)) } } pub use crate :: HfBuiltWithId ; # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfBuiltWithId < 'a > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfBuiltWithId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (self . tokens)) } }
[INFO] [stdout] 1 + pub use std :: collections :: BTreeMap ; pub use std :: marker :: PhantomData ; pub use hydroflow :: scheduled :: context :: Context ; pub use hydroflow :: scheduled :: graph :: Hydroflow ; pub use hydroflow :: * ; pub use lang :: graph :: { partition_graph , HydroflowGraph } ; pub use proc_macro2 :: TokenStream ; pub use quote :: quote ; pub use stageleft :: runtime_support :: FreeVariable ; pub use stageleft :: Quoted ; pub mod runtime_support { pub use bincode ; } pub mod stream { pub use std :: cell :: RefCell ; pub use std :: hash :: Hash ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow :: bytes :: Bytes ; pub use hydroflow :: futures :: Sink ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: quote ; pub use serde :: de :: DeserializeOwned ; pub use serde :: Serialize ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use syn :: parse_quote ; pub use crate :: builder :: { ClusterIds , FlowLeaves } ; pub use crate :: cycle :: { CycleCollection , CycleComplete } ; pub use crate :: ir :: { DebugInstantiate , HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { CanSend , Location , LocationId } ; pub use crate :: { Cluster , Optional , Singleton } ; pub use crate :: stream :: Unbounded ; pub use crate :: stream :: Bounded ; pub use crate :: stream :: NoTick ; pub use crate :: stream :: Tick ; pub use crate :: stream :: Stream ; # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Stream { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Stream < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Stream { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , C , N > > ,) -> Stream < 'a , (T , O) , W , C , N > where O : Clone , { let other : Optional < 'a , O , Bounded , C , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn cross_product < O > (self , other : Stream < 'a , O , W , C , N >) -> Stream < 'a , (T , O) , W , C , N > where T : Clone , O : Clone , { if self . location_kind != other . location_kind { panic ! ("cross_product must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossProduct (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn union (self , other : Stream < 'a , T , W , C , N >) -> Stream < 'a , T , W , C , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn dest_sink < S : Unpin + Sink < T > + 'a > (self , sink : impl Quoted < 'a , S >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: DestSink { sink : sink . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn first (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } # [doc = " Allow this stream through if the other stream has elements, otherwise the output is empty."] pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } # [doc = " Allow this stream through if the other stream is empty, otherwise the output is empty."] pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn enumerate (self) -> Stream < 'a , (usize , T) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Enumerate (Box :: new (self . ir_node . into_inner ())) ,) } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn sort (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Ord , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Sort (Box :: new (self . ir_node . into_inner ())) ,) } pub fn count (self) -> Singleton < 'a , usize , Bounded , Tick , N > { self . fold (q ! (|| 0usize) , q ! (| count , _ | * count += 1)) } pub fn delta (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } pub fn unique (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Eq + Hash , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unique (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn tick_batch (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_prefix (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { self . tick_batch () . persist () } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn for_each < F : Fn (T) + 'a > (self , f : impl IntoQuotedMut < 'a , F >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: ForEach { input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , f : f . splice () . into () , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Unbounded , NoTick , N > { pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . tick_batch () . continue_if (samples . first ()) . all_ticks () } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Unbounded , NoTick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , C , N : Location > Stream < 'a , T , Bounded , C , N > { pub fn filter_not_in (self , other : Stream < 'a , T , Bounded , C , N >) -> Stream < 'a , T , Bounded , C , N > where T : Eq + Hash , { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Difference (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Stream < 'a , & T , W , C , N > { pub fn cloned (self) -> Stream < 'a , T , W , C , N > { self . map (q ! (| d | d . clone ())) } } # [cfg (stageleft_macro)] impl < 'a , K , V1 , W , C , N : Location > Stream < 'a , (K , V1) , W , C , N > { pub fn join < W2 , V2 > (self , n : Stream < 'a , (K , V2) , W2 , C , N > ,) -> Stream < 'a , (K , (V1 , V2)) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Join (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } pub fn anti_join < W2 > (self , n : Stream < 'a , K , W2 , C , N >) -> Stream < 'a , (K , V1) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("anti_join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: AntiJoin (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , K : Eq + Hash , V , N : Location > Stream < 'a , (K , V) , Bounded , Tick , N > { pub fn fold_keyed < A , I : Fn () -> A + 'a , F : Fn (& mut A , V) + 'a > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , A) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FoldKeyed { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce_keyed < F : Fn (& mut V , V) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , V) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: ReduceKeyed { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } pub fn get_this_crate () -> TokenStream { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , Span :: call_site ()) ; quote ! { # ident } } } } pub fn serialize_bincode < T : Serialize > (is_demux : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if is_demux { parse_quote ! { map (| (id , data) | { (id , # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into ()) }) } } else { parse_quote ! { map (| data | { # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into () }) } } } pub fn deserialize_bincode < T : DeserializeOwned > (tagged : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if tagged { parse_quote ! { map (| res | { let (id , b) = res . unwrap () ; (id , # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& b) . unwrap ()) }) } } else { parse_quote ! { map (| res | { # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& res . unwrap ()) . unwrap () }) } } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn send_bincode < N2 : Location , CoreType > (self , other : & N2 ,) -> Stream < 'a , N :: Out < CoreType > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T > , CoreType : Serialize + DeserializeOwned , { let serialize_pipeline = Some (serialize_bincode :: < CoreType > (N :: is_demux ())) ; let deserialize_pipeline = Some (deserialize_bincode :: < CoreType > (N :: is_tagged ())) ; Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bytes < N2 : Location > (self , other : & N2 ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T > , { Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline : None , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline : if N :: is_tagged () { Some (parse_quote ! (map (| (id , b) | (id , b . unwrap () . freeze ())))) } else { Some (parse_quote ! (map (| b | b . unwrap () . freeze ()))) } , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bincode_interleaved < N2 : Location , Tag , CoreType > (self , other : & N2 ,) -> Stream < 'a , CoreType , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T , Out < CoreType > = (Tag , CoreType) > , CoreType : Serialize + DeserializeOwned , { self . send_bincode :: < N2 , CoreType > (other) . map (q ! (| (_ , b) | b)) } pub fn send_bytes_interleaved < N2 : Location , Tag > (self , other : & N2 ,) -> Stream < 'a , Bytes , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T , Out < Bytes > = (Tag , Bytes) > , { self . send_bytes :: < N2 > (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bincode < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < T > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) > , T : Clone + Serialize + DeserializeOwned , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bincode (other) } pub fn broadcast_bincode_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , T , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) , Out < T > = (Tag , T) > + 'a , T : Clone + Serialize + DeserializeOwned , { self . broadcast_bincode (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bytes < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) > + 'a , T : Clone , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bytes (other) } pub fn broadcast_bytes_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , Bytes , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) , Out < Bytes > = (Tag , Bytes) > + 'a , T : Clone , { self . broadcast_bytes (other) . map (q ! (| (_ , b) | b)) } } } pub use stream :: { Bounded , NoTick , Stream , Tick , Unbounded } ; pub mod singleton { pub use std :: cell :: RefCell ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use crate :: builder :: FlowLeaves ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial , CycleComplete } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: Stream ; pub use crate :: singleton :: CrossResult ; # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Singleton < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Singleton :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } pub use crate :: singleton :: Singleton ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Singleton { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleComplete < 'a > for Singleton < 'a , T , Bounded , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleCollectionWithInitial < 'a > for Singleton < 'a , T , Bounded , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , initial : Self , l : LocationId ,) -> Self { Singleton :: new (l , ir_leaves , HfPlusNode :: Union (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , }) , initial . ir_node . into_inner () . into () ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Singleton < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Singleton { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , U , W , C , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (Self :: other_ir_node (other)) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Singleton < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CrossSingleton (Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , Box :: new (HfPlusNode :: Unpersist (Box :: new (Self :: other_ir_node (other)))) ,))) ,) } } pub use crate :: singleton :: Optional ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Optional { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } pub fn some (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: new (singleton . location_kind , singleton . ir_leaves , singleton . ir_node . into_inner () ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > From < Singleton < 'a , T , W , C , N > > for Optional < 'a , T , W , C , N > { fn from (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: some (singleton) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Optional < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Optional { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn into_stream (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , Tick , N > > ,) -> Optional < 'a , (T , O) , Bounded , Tick , N > where O : Clone , { let other : Optional < 'a , O , Bounded , Tick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn union (self , other : Optional < 'a , T , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Optional < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_samples (self) -> Stream < 'a , T , Unbounded , NoTick , N > { self . latest_tick () . all_ticks () } pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . latest_tick () . continue_if (samples . first ()) . latest () . tick_samples () } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Unbounded , NoTick , N > > ,) -> Optional < 'a , (T , O) , Unbounded , NoTick , N > where O : Clone , { let other : Optional < 'a , O , Unbounded , NoTick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } self . latest_tick () . cross_singleton (other . latest_tick ()) . latest () } } } pub use singleton :: { Optional , Singleton } ; pub mod location { pub use std :: marker :: PhantomData ; pub use crate :: location :: LocationId ; pub use crate :: location :: Location ; pub use crate :: location :: Process ; # [cfg (stageleft_macro)] impl < P > Clone for Process < P > { fn clone (& self) -> Self { Process { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < P > Location for Process < P > { fn id (& self) -> LocationId { LocationId :: Process (self . id) } } pub use crate :: location :: Cluster ; # [cfg (stageleft_macro)] impl < C > Clone for Cluster < C > { fn clone (& self) -> Self { Cluster { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < C > Location for Cluster < C > { fn id (& self) -> LocationId { LocationId :: Cluster (self . id) } } pub use crate :: location :: CanSend ; # [cfg (stageleft_macro)] impl < P1 , P2 > CanSend < Process < P2 > > for Process < P1 > { type In < T > = T ; type Out < T > = T ; fn is_demux () -> bool { false } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < P1 , C2 > CanSend < Cluster < C2 > > for Process < P1 > { type In < T > = (u32 , T) ; type Out < T > = T ; fn is_demux () -> bool { true } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < C1 , P2 > CanSend < Process < P2 > > for Cluster < C1 > { type In < T > = T ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { false } fn is_tagged () -> bool { true } } # [cfg (stageleft_macro)] impl < C1 , C2 > CanSend < Cluster < C2 > > for Cluster < C1 > { type In < T > = (u32 , T) ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { true } fn is_tagged () -> bool { true } } } pub use location :: { Cluster , Process } ; pub mod deploy { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use stageleft :: Quoted ; pub mod graphs { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use super :: { LocalDeploy , Node , ProcessSpec } ; pub use crate :: deploy :: graphs :: SingleProcessGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for SingleProcessGraph { type Process = SingleNode ; type Cluster = SingleNode ; type Meta = () ; type GraphId = () ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { SingleNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { SingleNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , SingleProcessGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> SingleNode { SingleNode { } } } pub use crate :: deploy :: graphs :: SingleNode ; # [cfg (stageleft_macro)] impl Node for SingleNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } pub use crate :: deploy :: graphs :: MultiGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for MultiGraph { type Process = MultiNode ; type Cluster = MultiNode ; type Meta = () ; type GraphId = usize ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { MultiNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { MultiNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , MultiGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> MultiNode { MultiNode { } } } pub use crate :: deploy :: graphs :: MultiNode ; # [cfg (stageleft_macro)] impl Node for MultiNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } } pub use graphs :: * ; pub use crate :: deploy :: LocalDeploy ; pub use crate :: deploy :: Deploy ; # [cfg (stageleft_macro)] impl < 'a , T : Deploy < 'a , Process = N , Cluster = C , Meta = M , GraphId = R > , N : Node < Meta = M > , C : Node < Meta = M > , M : Default , R , > LocalDeploy < 'a > for T { type Process = N ; type Cluster = C ; type Meta = M ; type GraphId = R ; fn has_trivial_node () -> bool { < T as Deploy < 'a > > :: has_trivial_node () } fn trivial_process (id : usize) -> Self :: Process { < T as Deploy < 'a > > :: trivial_process (id) } fn trivial_cluster (id : usize) -> Self :: Cluster { < T as Deploy < 'a > > :: trivail_cluster (id) } } pub use crate :: deploy :: ProcessSpec ; pub use crate :: deploy :: ClusterSpec ; pub use crate :: deploy :: Node ; } pub use deploy :: { ClusterSpec , Deploy , ProcessSpec } ; pub mod cycle { pub use std :: marker :: PhantomData ; pub use crate :: builder :: FlowLeaves ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: cycle :: CycleComplete ; pub use crate :: cycle :: CycleCollection ; pub use crate :: cycle :: CycleCollectionWithInitial ; pub use crate :: cycle :: HfCycle ; # [cfg (stageleft_macro)] impl < 'a , S : CycleComplete < 'a > > HfCycle < 'a , S > { pub fn complete (self , stream : S) { let ident = self . ident ; S :: complete (stream , ident) } } } pub use cycle :: HfCycle ; pub mod builder { pub use std :: cell :: RefCell ; pub use std :: collections :: HashMap ; pub use std :: marker :: PhantomData ; pub use std :: rc :: Rc ; pub use std :: time :: Duration ; pub use hydroflow :: futures :: stream :: Stream as FuturesStream ; pub use hydroflow :: { tokio , tokio_stream } ; pub use internal :: TokenStream ; pub use proc_macro2 :: Span ; pub use quote :: quote ; pub use runtime_support :: FreeVariable ; pub use stageleft :: * ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Cluster , Location , LocationId , Process } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: { HfCycle , Optional , RuntimeContext , Singleton , Stream } ; pub mod built { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use hydroflow_lang :: graph :: { eliminate_extra_unions_tees , HydroflowGraph } ; pub use super :: deploy :: { DeployFlow , DeployResult } ; pub use crate :: deploy :: { ClusterSpec , Deploy , LocalDeploy , ProcessSpec } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Cluster , Process } ; pub use crate :: HfCompiled ; pub use crate :: builder :: built :: BuiltFlow ; # [cfg (stageleft_macro)] impl < 'a > Drop for BuiltFlow < 'a > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped BuiltFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn ir (& self) -> & Vec < HfPlusLeaf < 'a > > { & self . ir } pub fn optimize_with (mut self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> BuiltFlow < 'a > { self . used = true ; BuiltFlow { ir : f (std :: mem :: take (& mut self . ir)) , processes : std :: mem :: take (& mut self . processes) , clusters : std :: mem :: take (& mut self . clusters) , used : false , _phantom : PhantomData , } } } pub fn build_inner (ir : & mut Vec < HfPlusLeaf >) -> BTreeMap < usize , HydroflowGraph > { let mut builders = BTreeMap :: new () ; let mut built_tees = HashMap :: new () ; let mut next_stmt_id = 0 ; for leaf in ir { leaf . emit (& mut builders , & mut built_tees , & mut next_stmt_id) ; } builders . into_iter () . map (| (k , v) | { let (mut flat_graph , _ , _) = v . build () ; eliminate_extra_unions_tees (& mut flat_graph) ; (k , flat_graph) }) . collect () } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn compile_no_network < D : LocalDeploy < 'a > > (mut self) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; HfCompiled { hydroflow_ir : build_inner (& mut self . ir) , extra_stmts : BTreeMap :: new () , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> BuiltFlow < 'a > { self . optimize_with (crate :: persist_pullup :: persist_pullup) } fn into_deploy < D : LocalDeploy < 'a > > (mut self) -> DeployFlow < 'a , D > { self . used = true ; let processes = if D :: has_trivial_node () { self . processes . iter () . map (| id | (* id , D :: trivial_process (* id))) . collect () } else { HashMap :: new () } ; let clusters = if D :: has_trivial_node () { self . clusters . iter () . map (| id | (* id , D :: trivial_cluster (* id))) . collect () } else { HashMap :: new () } ; DeployFlow { ir : std :: mem :: take (& mut self . ir) , nodes : processes , clusters , used : false , _phantom : PhantomData , } } pub fn with_process < P , D : LocalDeploy < 'a > > (self , process : & Process < P > , spec : impl ProcessSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_process (process , spec) } pub fn with_cluster < C , D : LocalDeploy < 'a > > (self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_cluster (cluster , spec) } pub fn compile < D : Deploy < 'a > + 'a > (self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . into_deploy :: < D > () . compile (env) } pub fn deploy < D : Deploy < 'a , CompileEnv = () > + 'a > (self , env : & mut D :: InstantiateEnv ,) -> DeployResult < 'a , D > { self . into_deploy :: < D > () . deploy (env) } } } pub mod deploy { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use proc_macro2 :: Span ; pub use stageleft :: Quoted ; pub use super :: built :: build_inner ; pub use crate :: deploy :: { LocalDeploy , Node } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: { Cluster , ClusterSpec , Deploy , HfCompiled , Process , ProcessSpec } ; pub use crate :: builder :: deploy :: DeployFlow ; # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > Drop for DeployFlow < 'a , D > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped DeployFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > DeployFlow < 'a , D > { pub fn with_process < P > (mut self , process : & Process < P > , spec : impl ProcessSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < P > () . to_string () ; self . nodes . insert (process . id , spec . build (process . id , & tag_name)) ; self } pub fn with_cluster < C > (mut self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < C > () . to_string () ; self . clusters . insert (cluster . id , spec . build (cluster . id , & tag_name)) ; self } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployFlow < 'a , D > { pub fn compile (mut self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; let mut seen_tees : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | leaf . compile_network :: < D > (env , & mut seen_tees , & self . nodes , & self . clusters)) . collect () ; let extra_stmts = self . extra_stmts (env) ; HfCompiled { hydroflow_ir : build_inner (& mut ir_leaves_networked) , extra_stmts , _phantom : PhantomData , } } fn extra_stmts (& self , env : & < D as Deploy < 'a > > :: CompileEnv) -> BTreeMap < usize , Vec < syn :: Stmt > > { let all_locations_count = self . nodes . len () + self . clusters . len () ; let mut extra_stmts : BTreeMap < usize , Vec < syn :: Stmt > > = BTreeMap :: new () ; for & c_id in self . clusters . keys () { let self_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , c_id) , Span :: call_site () ,) ; let self_id_expr = D :: cluster_self_id (env) . splice () ; extra_stmts . entry (c_id) . or_default () . push (syn :: parse_quote ! { let # self_id_ident = # self_id_expr ; }) ; for other_location in 0 .. all_locations_count { let other_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , c_id) , Span :: call_site () ,) ; let other_id_expr = D :: cluster_ids (env , c_id) . splice () ; extra_stmts . entry (other_location) . or_default () . push (syn :: parse_quote ! { let # other_id_ident = # other_id_expr ; }) ; } } extra_stmts } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a , CompileEnv = () > > DeployFlow < 'a , D > { # [must_use] pub fn deploy (mut self , env : & mut D :: InstantiateEnv) -> DeployResult < 'a , D > { self . used = true ; let mut seen_tees_instantiate : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | { leaf . compile_network :: < D > (& () , & mut seen_tees_instantiate , & self . nodes , & self . clusters ,) }) . collect () ; let mut compiled = build_inner (& mut ir_leaves_networked) ; let mut extra_stmts = self . extra_stmts (& ()) ; let mut meta = D :: Meta :: default () ; let (mut processes , mut clusters) = (std :: mem :: take (& mut self . nodes) . into_iter () . map (| (node_id , node) | { node . instantiate (env , & mut meta , compiled . remove (& node_id) . unwrap () , extra_stmts . remove (& node_id) . unwrap_or_default () ,) ; (node_id , node) }) . collect :: < HashMap < _ , _ > > () , std :: mem :: take (& mut self . clusters) . into_iter () . map (| (cluster_id , cluster) | { cluster . instantiate (env , & mut meta , compiled . remove (& cluster_id) . unwrap () , extra_stmts . remove (& cluster_id) . unwrap_or_default () ,) ; (cluster_id , cluster) }) . collect :: < HashMap < _ , _ > > () ,) ; for node in processes . values_mut () { node . update_meta (& meta) ; } for cluster in clusters . values_mut () { cluster . update_meta (& meta) ; } let mut seen_tees_connect = HashMap :: new () ; for leaf in ir_leaves_networked { leaf . connect_network (& mut seen_tees_connect) ; } DeployResult { processes , clusters , } } } pub use crate :: builder :: deploy :: DeployResult ; # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployResult < 'a , D > { pub fn get_process < P > (& self , p : & Process < P >) -> & D :: Process { let id = match p . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . processes . get (& id) . unwrap () } pub fn get_cluster < C > (& self , c : & Cluster < C >) -> & D :: Cluster { let id = match c . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . clusters . get (& id) . unwrap () } } } # [doc = " Tracks the leaves of the dataflow IR. This is referenced by"] # [doc = " `Stream` and `HfCycle` to build the IR. The inner option will"] # [doc = " be set to `None` when this builder is finalized."] pub type FlowLeaves < 'a > = Rc < RefCell < Option < Vec < HfPlusLeaf < 'a > > > > > ; pub use crate :: builder :: ClusterIds ; # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Vec < u32 > > for ClusterIds < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , & 'a Vec < u32 > > for ClusterIds < 'a > { } # [derive (Copy , Clone)] pub struct ClusterSelfId < 'a > { pub id : usize , pub _phantom : PhantomData < & 'a mut & 'a u32 > , } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < u32 > for ClusterSelfId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , u32 > for ClusterSelfId < 'a > { } pub use crate :: builder :: FlowBuilder ; # [cfg (stageleft_macro)] impl < 'a > Drop for FlowBuilder < 'a > { fn drop (& mut self) { if ! self . finalized { panic ! ("Dropped FlowBuilder without finalizing, you may have forgotten to call `with_default_optimize`, `optimize_with`, or `finalize`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > QuotedContext for FlowBuilder < 'a > { fn create () -> Self { FlowBuilder :: new () } } # [cfg (stageleft_macro)] impl < 'a > FlowBuilder < 'a > { # [allow (clippy :: new_without_default)] pub fn new () -> FlowBuilder < 'a > { FlowBuilder { ir_leaves : Rc :: new (RefCell :: new (Some (Vec :: new ()))) , nodes : RefCell :: new (vec ! []) , clusters : RefCell :: new (vec ! []) , cycle_ids : RefCell :: new (HashMap :: new ()) , next_node_id : RefCell :: new (0) , finalized : false , _phantom : PhantomData , } } pub fn finalize (mut self) -> built :: BuiltFlow < 'a > { self . finalized = true ; built :: BuiltFlow { ir : self . ir_leaves . borrow_mut () . take () . unwrap () , processes : self . nodes . replace (vec ! []) , clusters : self . clusters . replace (vec ! []) , used : false , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> built :: BuiltFlow < 'a > { self . finalize () . with_default_optimize () } pub fn optimize_with (self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> built :: BuiltFlow < 'a > { self . finalize () . optimize_with (f) } pub fn ir_leaves (& self) -> & FlowLeaves < 'a > { & self . ir_leaves } pub fn process < P > (& self) -> Process < P > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . nodes . borrow_mut () . push (id) ; Process { id , _phantom : PhantomData , } } pub fn cluster < C > (& self) -> Cluster < C > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . clusters . borrow_mut () . push (id) ; Cluster { id , _phantom : PhantomData , } } pub fn runtime_context (& self) -> RuntimeContext < 'a > { RuntimeContext { _phantom : PhantomData , } } pub fn cluster_members < C > (& self , cluster : & Cluster < C > ,) -> impl Quoted < 'a , & 'a Vec < u32 > > + Copy + 'a { ClusterIds { id : cluster . id , _phantom : PhantomData , } } pub fn cluster_self_id < C > (& self , cluster : & Cluster < C >) -> impl Quoted < 'a , u32 > + Copy + 'a { ClusterSelfId { id : cluster . id , _phantom : PhantomData , } } pub fn spin < L : Location > (& self , on : & L) -> Stream < 'a , () , Unbounded , NoTick , L > { Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Spin () , location_kind : on . id () , })) ,) } pub fn spin_batch < L : Location > (& self , on : & L , batch_size : impl Quoted < 'a , usize > + Copy + 'a ,) -> Stream < 'a , () , Bounded , Tick , L > { self . spin (on) . flat_map (q ! (move | _ | 0 .. batch_size)) . map (q ! (| _ | ())) . tick_batch () } pub fn source_stream < T , E : FuturesStream < Item = T > + Unpin , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Unbounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Stream (e . into ()) , location_kind : on . id () , })) ,) } pub fn source_iter < T , E : IntoIterator < Item = T > , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Bounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , })) ,) } pub fn singleton < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Singleton < 'a , T , Bounded , NoTick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Singleton :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,)))) ,) } pub fn singleton_first_tick < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Optional < 'a , T , Bounded , Tick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,) } pub fn source_interval < L : Location > (& self , on : & L , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , () , Unbounded , NoTick , L > { let interval = interval . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : on . id () , })) ,) } pub fn source_interval_delayed < L : Location > (& self , on : & L , delay : impl Quoted < 'a , Duration > + Copy + 'a , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , tokio :: time :: Instant , Unbounded , NoTick , L > { self . source_stream (on , q ! (tokio_stream :: wrappers :: IntervalStream :: new (tokio :: time :: interval_at (tokio :: time :: Instant :: now () + delay , interval))) ,) . tick_batch () . first () . latest () } pub fn cycle < S : CycleCollection < 'a > > (& self , on : & S :: Location) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , on . id ()) ,) } pub fn cycle_with_initial < S : CycleCollectionWithInitial < 'a > > (& self , on : & S :: Location , initial : S ,) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , initial , on . id ()) ,) } } } pub use builder :: FlowBuilder ; pub mod ir { pub use core :: panic ; pub use std :: cell :: RefCell ; pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow_lang :: graph :: FlatGraphBuilder ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: ToTokens ; pub use syn :: parse_quote ; pub use crate :: deploy :: Deploy ; pub use crate :: location :: LocationId ; pub use crate :: ir :: DebugExpr ; # [cfg (stageleft_macro)] impl From < syn :: Expr > for DebugExpr { fn from (expr : syn :: Expr) -> DebugExpr { DebugExpr (expr) } } # [cfg (stageleft_macro)] impl Deref for DebugExpr { type Target = syn :: Expr ; fn deref (& self) -> & Self :: Target { & self . 0 } } # [cfg (stageleft_macro)] impl ToTokens for DebugExpr { fn to_tokens (& self , tokens : & mut TokenStream) { self . 0 . to_tokens (tokens) ; } } # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugExpr { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "{}" , self . 0 . to_token_stream ()) } } pub use crate :: ir :: DebugInstantiate ; # [cfg (stageleft_macro)] impl < 'a > std :: fmt :: Debug for DebugInstantiate < 'a > { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<network instantiate>") } } pub use crate :: ir :: DebugPipelineFn ; # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugPipelineFn { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<function>") } } pub use crate :: ir :: HfPlusSource ; pub use crate :: ir :: HfPlusLeaf ; # [cfg (stageleft_macro)] impl < 'a > HfPlusLeaf < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . compile_network :: < D > (compile_env , s , nodes , clusters) ; } , seen_tees ,) } pub fn connect_network (self , seen_tees : & mut SeenTees < 'a >) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . connect_network (s) ; } , seen_tees ,) } pub fn transform_children (self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) -> HfPlusLeaf < 'a > { match self { HfPlusLeaf :: ForEach { f , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: ForEach { f , input } } HfPlusLeaf :: DestSink { sink , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: DestSink { sink , input } } HfPlusLeaf :: CycleSink { ident , location_kind , mut input , } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: CycleSink { ident , location_kind , input , } } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) { match self { HfPlusLeaf :: ForEach { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> for_each (# f) ; }) ; } HfPlusLeaf :: DestSink { sink , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink) ; }) ; } HfPlusLeaf :: CycleSink { ident , location_kind , input , } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; assert_eq ! (input_location_id , * location_id , "cycle_sink location mismatch") ; graph_builders . entry (* location_id) . or_default () . add_statement (parse_quote ! { # ident = # input_ident ; }) ; } } } } pub use crate :: ir :: HfPlusNode ; pub type SeenTees < 'a > = HashMap < * const RefCell < HfPlusNode < 'a > > , Rc < RefCell < HfPlusNode < 'a > > > > ; # [cfg (stageleft_macro)] impl < 'a > HfPlusNode < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (& mut self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) { self . transform_children (| n , s | n . compile_network :: < D > (compile_env , s , nodes , clusters) , seen_tees ,) ; if let HfPlusNode :: Network { from_location , to_location , instantiate_fn , .. } = self { let (sink_expr , source_expr , connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { let ((sink , source) , connect_fn) = match (from_location , to_location) { (LocationId :: Process (from) , LocationId :: Process (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: o2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Process (from) , LocationId :: Cluster (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: o2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Process (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: m2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Cluster (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: m2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } } ; (sink , source , connect_fn) } DebugInstantiate :: Finalized (_ , _ , _) => panic ! ("network already finalized") , } ; * instantiate_fn = DebugInstantiate :: Finalized (sink_expr , source_expr , connect_fn) ; } } pub fn connect_network (& mut self , seen_tees : & mut SeenTees < 'a >) { self . transform_children (| n , s | n . connect_network (s) , seen_tees) ; if let HfPlusNode :: Network { instantiate_fn , .. } = self { match instantiate_fn { DebugInstantiate :: Building () => panic ! ("network not built") , DebugInstantiate :: Finalized (_ , _ , ref connect_fn) => { connect_fn () ; } } } } pub fn transform_children (& mut self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) { match self { HfPlusNode :: Placeholder => { panic ! () ; } HfPlusNode :: Source { .. } => { } HfPlusNode :: CycleSource { .. } => { } HfPlusNode :: Tee { inner } => { if let Some (transformed) = seen_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { * inner = transformed . clone () ; } else { let transformed_cell = Rc :: new (RefCell :: new (HfPlusNode :: Placeholder)) ; seen_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , transformed_cell . clone () ,) ; let mut orig = inner . replace (HfPlusNode :: Placeholder) ; transform (& mut orig , seen_tees) ; * transformed_cell . borrow_mut () = orig ; * inner = transformed_cell ; } } HfPlusNode :: Persist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Unpersist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Delta (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Union (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossProduct (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossSingleton (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Join (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Difference (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: AntiJoin (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Map { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FlatMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Filter { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FilterMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Sort (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: DeferTick (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Enumerate (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Inspect { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Unique (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Fold { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FoldKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Reduce { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: ReduceKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Network { input , .. } => { transform (input . as_mut () , seen_tees) ; } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) -> (syn :: Ident , usize) { match self { HfPlusNode :: Placeholder => { panic ! () } HfPlusNode :: Persist (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let persist_id = * next_stmt_id ; * next_stmt_id += 1 ; let persist_ident = syn :: Ident :: new (& format ! ("stream_{}" , persist_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # persist_ident = # inner_ident -> persist ::<'static > () ; }) ; (persist_ident , location) } HfPlusNode :: Unpersist (_) => { panic ! ("Unpersist is a marker node and should have been optimized away. This is likely a compiler bug.") } HfPlusNode :: Delta (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let delta_id = * next_stmt_id ; * next_stmt_id += 1 ; let delta_ident = syn :: Ident :: new (& format ! ("stream_{}" , delta_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # delta_ident = # inner_ident -> multiset_delta () ; }) ; (delta_ident , location) } HfPlusNode :: Source { source , location_kind , } => { let source_id = * next_stmt_id ; * next_stmt_id += 1 ; let source_ident = syn :: Ident :: new (& format ! ("stream_{}" , source_id) , Span :: call_site ()) ; let source_stmt = match source { HfPlusSource :: Stream (expr) => { parse_quote ! { # source_ident = source_stream (# expr) ; } } HfPlusSource :: Iter (expr) => { parse_quote ! { # source_ident = source_iter (# expr) ; } } HfPlusSource :: Interval (expr) => { parse_quote ! { # source_ident = source_interval (# expr) ; } } HfPlusSource :: Spin () => { parse_quote ! { # source_ident = spin () ; } } } ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; graph_builders . entry (* location_id) . or_default () . add_statement (source_stmt) ; (source_ident , * location_id) } HfPlusNode :: CycleSource { ident , location_kind , } => { let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; (ident . clone () , * location_id) } HfPlusNode :: Tee { inner } => { if let Some (ret) = built_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { ret . clone () } else { let (inner_ident , inner_location_id) = inner . borrow () . emit (graph_builders , built_tees , next_stmt_id) ; let tee_id = * next_stmt_id ; * next_stmt_id += 1 ; let tee_ident = syn :: Ident :: new (& format ! ("stream_{}" , tee_id) , Span :: call_site ()) ; let builder = graph_builders . entry (inner_location_id) . or_default () ; builder . add_statement (parse_quote ! { # tee_ident = # inner_ident -> tee () ; }) ; built_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , (tee_ident . clone () , inner_location_id) ,) ; (tee_ident , inner_location_id) } } HfPlusNode :: Union (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "union inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let union_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # union_ident = union () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [0] # union_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # union_ident ; }) ; (union_ident , left_location_id) } HfPlusNode :: CrossSingleton (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "cross_singleton inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let cross_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # cross_ident = cross_singleton () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [input] # cross_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [single] # cross_ident ; }) ; (cross_ident , left_location_id) } HfPlusNode :: CrossProduct (..) | HfPlusNode :: Join (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: CrossProduct (..)) { parse_quote ! (cross_join_multiset) } else { parse_quote ! (join_multiset) } ; let (HfPlusNode :: CrossProduct (left , right) | HfPlusNode :: Join (left , right)) = self else { unreachable ! () } ; let (left_inner , left_was_persist) = if let HfPlusNode :: Persist (left) = left . as_ref () { (left , true) } else { (left , false) } ; let (right_inner , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left_inner . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right_inner . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "join / cross product inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; match (left_was_persist , right_was_persist) { (true , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'static > () ; }) ; } (true , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'tick > () ; }) ; } (false , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } (false , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } } ; builder . add_statement (parse_quote ! { # left_ident -> [0] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Difference (..) | HfPlusNode :: AntiJoin (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Difference (..)) { parse_quote ! (difference_multiset) } else { parse_quote ! (anti_join_multiset) } ; let (HfPlusNode :: Difference (left , right) | HfPlusNode :: AntiJoin (left , right)) = self else { unreachable ! () } ; let (right , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "difference / anti join inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; if right_was_persist { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } else { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } builder . add_statement (parse_quote ! { # left_ident -> [pos] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [neg] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Map { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let map_id = * next_stmt_id ; * next_stmt_id += 1 ; let map_ident = syn :: Ident :: new (& format ! ("stream_{}" , map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # map_ident = # input_ident -> map (# f) ; }) ; (map_ident , input_location_id) } HfPlusNode :: FlatMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let flat_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let flat_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , flat_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # flat_map_ident = # input_ident -> flat_map (# f) ; }) ; (flat_map_ident , input_location_id) } HfPlusNode :: Filter { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_ident = # input_ident -> filter (# f) ; }) ; (filter_ident , input_location_id) } HfPlusNode :: FilterMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_map_ident = # input_ident -> filter_map (# f) ; }) ; (filter_map_ident , input_location_id) } HfPlusNode :: Sort (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sort_id = * next_stmt_id ; * next_stmt_id += 1 ; let sort_ident = syn :: Ident :: new (& format ! ("stream_{}" , sort_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # sort_ident = # input_ident -> sort () ; }) ; (sort_ident , input_location_id) } HfPlusNode :: DeferTick (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let defer_tick_id = * next_stmt_id ; * next_stmt_id += 1 ; let defer_tick_ident = syn :: Ident :: new (& format ! ("stream_{}" , defer_tick_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # defer_tick_ident = # input_ident -> defer_tick_lazy () ; }) ; (defer_tick_ident , input_location_id) } HfPlusNode :: Enumerate (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let enumerate_id = * next_stmt_id ; * next_stmt_id += 1 ; let enumerate_ident = syn :: Ident :: new (& format ! ("stream_{}" , enumerate_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # enumerate_ident = # input_ident -> enumerate () ; }) ; (enumerate_ident , input_location_id) } HfPlusNode :: Inspect { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let inspect_id = * next_stmt_id ; * next_stmt_id += 1 ; let inspect_ident = syn :: Ident :: new (& format ! ("stream_{}" , inspect_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # inspect_ident = # input_ident -> inspect (# f) ; }) ; (inspect_ident , input_location_id) } HfPlusNode :: Unique (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let unique_id = * next_stmt_id ; * next_stmt_id += 1 ; let unique_ident = syn :: Ident :: new (& format ! ("stream_{}" , unique_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # unique_ident = # input_ident -> unique ::<'tick > () ; }) ; (unique_ident , input_location_id) } HfPlusNode :: Fold { .. } | HfPlusNode :: FoldKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Fold { .. }) { parse_quote ! (fold) } else { parse_quote ! (fold_keyed) } ; let (HfPlusNode :: Fold { init , acc , input } | HfPlusNode :: FoldKeyed { init , acc , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let fold_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'static > (# init , # acc) ; }) ; } else { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'tick > (# init , # acc) ; }) ; } (fold_ident , input_location_id) } HfPlusNode :: Reduce { .. } | HfPlusNode :: ReduceKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Reduce { .. }) { parse_quote ! (reduce) } else { parse_quote ! (reduce_keyed) } ; let (HfPlusNode :: Reduce { f , input } | HfPlusNode :: ReduceKeyed { f , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let reduce_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'static > (# f) ; }) ; } else { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'tick > (# f) ; }) ; } (reduce_ident , input_location_id) } HfPlusNode :: Network { from_location : _ , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input , } => { let (sink_expr , source_expr , _connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { panic ! ("Expected the network to be finalized") } DebugInstantiate :: Finalized (sink , source , connect_fn) => { (sink , source , connect_fn) } } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sender_builder = graph_builders . entry (input_location_id) . or_default () ; if let Some (serialize_pipeline) = serialize_pipeline { sender_builder . add_statement (parse_quote ! { # input_ident -> # serialize_pipeline -> dest_sink (# sink_expr) ; }) ; } else { sender_builder . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink_expr) ; }) ; } let to_id = match to_location { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let receiver_builder = graph_builders . entry (* to_id) . or_default () ; let receiver_stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let receiver_stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , receiver_stream_id) , Span :: call_site ()) ; if let Some (deserialize_pipeline) = deserialize_pipeline { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) -> # deserialize_pipeline ; }) ; } else { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) ; }) ; } (receiver_stream_ident , * to_id) } } } } } pub mod persist_pullup { pub use std :: cell :: RefCell ; pub use std :: collections :: HashSet ; pub use std :: ops :: Deref ; pub use crate :: ir :: * ; pub fn persist_pullup_node < 'a > (node : & mut HfPlusNode < 'a > , seen_tees : & mut SeenTees < 'a > , persist_pulled_tees : & mut HashSet < * const RefCell < HfPlusNode < 'a > > > ,) { node . transform_children (| n , s | persist_pullup_node (n , s , persist_pulled_tees) , seen_tees ,) ; match node { HfPlusNode :: Unpersist (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Unpersist (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Delta (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Delta (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Tee { inner } => { if persist_pulled_tees . contains (& (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >)) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } else { let inner_borrow = inner . borrow () ; if let HfPlusNode :: Persist (_) = inner_borrow . deref () { drop (inner_borrow) ; persist_pulled_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >) ; if let HfPlusNode :: Persist (box behind_persist) = inner . replace (HfPlusNode :: Placeholder) { * inner . borrow_mut () = behind_persist ; } else { unreachable ! () } * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } } } HfPlusNode :: Map { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Map { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Map { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: FlatMap { f : _ , input : HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: FlatMap { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: FlatMap { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Filter { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Filter { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Filter { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Network { input : box HfPlusNode :: Persist (_) , .. } => { if let HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Union (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Union (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Union (left , right))) ; } else { unreachable ! () } } HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: CrossProduct (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,) ,)))) ; } else { unreachable ! () } } HfPlusNode :: Join (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Join (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: Join (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,))))) ; } else { unreachable ! () } } _ => { } } } pub fn persist_pullup (ir : Vec < HfPlusLeaf >) -> Vec < HfPlusLeaf > { let mut seen_tees = Default :: default () ; let mut persist_pulled_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| n , s | persist_pullup_node (n , s , & mut persist_pulled_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn persist_pullup_through_map () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } # [test] fn persist_pullup_behind_tee () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; let before_tee = flow . source_iter (& process , q ! (0 .. 10)) . tick_batch () . persist () ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } } } pub mod profiler { pub use std :: cell :: RefCell ; pub use hydroflow :: futures :: channel :: mpsc :: UnboundedSender ; pub use stageleft :: * ; pub use crate as hydroflow_plus ; pub use crate :: ir :: * ; pub use crate :: RuntimeContext ; pub fn increment_counter (count : & mut u64) { * count += 1 ; } pub fn quoted_any_fn < 'a , F : Fn (& usize) + 'a , Q : IntoQuotedMut < 'a , F > > (q : Q) -> Q { q } # [doc = " Add a profiling node before each node to count the cardinality of its input"] pub fn add_profiling_node < 'a > (node : & mut HfPlusNode < 'a > , _context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > , id : & mut u32 , seen_tees : & mut SeenTees < 'a > ,) { let my_id = * id ; * id += 1 ; node . transform_children (| node , seen_tees | { add_profiling_node (node , _context , counters , counter_queue , id , seen_tees) } , seen_tees ,) ; let orig_node = std :: mem :: replace (node , HfPlusNode :: Placeholder) ; * node = HfPlusNode :: Inspect { f : quoted_any_fn (q ! ({ counter_queue . borrow () . unbounded_send ((my_id as usize , counters . borrow () [my_id as usize])) . unwrap () ; counters . borrow_mut () [my_id as usize] = 0 ; move | _ | { hydroflow_plus :: profiler :: increment_counter (& mut counters . borrow_mut () [my_id as usize] ,) ; } })) . splice () . into () , input : Box :: new (orig_node) , } } # [doc = " Count the cardinality of each input and periodically output to a file"] pub fn profiling < 'a > (ir : Vec < HfPlusLeaf < 'a > > , context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > ,) -> Vec < HfPlusLeaf < 'a > > { let mut id = 0 ; let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | { add_profiling_node (node , context , counters , counter_queue , & mut id , seen_tees) } , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn profiler_wrapping_all_operators () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let runtime_context = flow . runtime_context () ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (& built . ir ()) ; let counters = RuntimeData :: new ("Fake") ; let counter_queue = RuntimeData :: new ("Fake") ; let pushed_down = built . with_default_optimize () . optimize_with (| ir | super :: profiling (ir , runtime_context , counters , counter_queue)) ; insta :: assert_debug_snapshot ! (& pushed_down . ir ()) ; let _ = pushed_down . compile_no_network :: < MultiGraph > () ; } } } pub mod properties { pub use std :: collections :: HashSet ; pub use stageleft :: * ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , SeenTees } ; pub use crate :: properties :: PropertyDatabase ; # [doc = " Allows us to convert the hydroflow datatype for folds to a binary operation for the algebra"] # [doc = " property tests."] # [allow (dead_code)] pub fn convert_hf_to_binary < I , A : Default , F : Fn (& mut A , I) > (f : F) -> impl Fn (I , I) -> A { move | a , b | { let mut acc = Default :: default () ; f (& mut acc , a) ; f (& mut acc , b) ; acc } } # [cfg (stageleft_macro)] impl PropertyDatabase { # [doc = " Tags the expression as commutative."] pub fn add_commutative_tag < 'a , I , A , F : Fn (& mut A , I) , Q : Quoted < 'a , F > + Clone > (& mut self , expr : Q ,) -> Q { let expr_clone = expr . clone () ; self . commutative . insert (expr_clone . splice ()) ; expr } pub fn is_tagged_commutative (& self , expr : & syn :: Expr) -> bool { self . commutative . contains (expr) } } pub fn properties_optimize_node < 'a > (node : & mut HfPlusNode < 'a > , db : & PropertyDatabase , seen_tees : & mut SeenTees < 'a > ,) { node . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , seen_tees ,) ; match node { HfPlusNode :: ReduceKeyed { f , .. } if db . is_tagged_commutative (& f . 0) => { dbg ! ("IDENTIFIED COMMUTATIVE OPTIMIZATION for {:?}" , & f) ; } _ => { } } } pub fn properties_optimize < 'a > (ir : Vec < HfPlusLeaf < 'a > > , db : & PropertyDatabase ,) -> Vec < HfPlusLeaf < 'a > > { let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use super :: * ; use crate :: deploy :: SingleProcessGraph ; use crate :: FlowBuilder ; # [test] fn test_property_database () { let mut db = PropertyDatabase :: default () ; assert ! (! db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; let _ = db . add_commutative_tag (q ! (| a : & mut i32 , b : i32 | * a += b)) ; assert ! (db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; } # [test] fn test_property_optimized () { let flow = FlowBuilder :: new () ; let mut database = PropertyDatabase :: default () ; let process = flow . process :: < () > () ; let counter_func = q ! (| count : & mut i32 , _ | * count += 1) ; let _ = database . add_commutative_tag (counter_func) ; flow . source_iter (& process , q ! (vec ! [])) . map (q ! (| string : String | (string , ()))) . tick_batch () . fold_keyed (q ! (|| 0) , counter_func) . all_ticks () . for_each (q ! (| (string , count) | println ! ("{}: {}" , string , count))) ; let built = flow . finalize () . optimize_with (| ir | properties_optimize (ir , & database)) . with_default_optimize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let _ = built . compile_no_network :: < SingleProcessGraph > () ; } } } pub use crate :: RuntimeContext ; # [cfg (stageleft_macro)] impl Copy for RuntimeContext < '_ > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Context > for RuntimeContext < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (quote ! (& context))) } } pub use crate :: HfCompiled ; # [cfg (stageleft_macro)] impl < 'a , ID > HfCompiled < 'a , ID > { pub fn hydroflow_ir (& self) -> & BTreeMap < usize , HydroflowGraph > { & self . hydroflow_ir } } # [cfg (stageleft_macro)] impl < 'a > HfCompiled < 'a , usize > { pub fn with_dynamic_id (self , id : impl Quoted < 'a , usize >) -> HfBuiltWithId < 'a > { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; let mut conditioned_tokens = None ; for (subgraph_id , flat_graph) in self . hydroflow_ir { let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; let my_extra_stmts = self . extra_stmts . get (& subgraph_id) . cloned () . unwrap_or_default () ; if let Some (conditioned_tokens) = conditioned_tokens . as_mut () { * conditioned_tokens = syn :: parse_quote ! { # conditioned_tokens else if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } } ; } else { conditioned_tokens = Some (syn :: parse_quote ! { if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } }) ; } } let conditioned_tokens : TokenStream = conditioned_tokens . unwrap () ; let id = id . splice () ; HfBuiltWithId { tokens : syn :: parse_quote ! ({ let __given_id = # id ; # conditioned_tokens else { panic ! ("Invalid node id: {}" , __given_id) ; } }) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfCompiled < 'a , () > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfCompiled < 'a , () > { fn to_tokens (mut self) -> (Option < TokenStream > , Option < TokenStream >) { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; if self . hydroflow_ir . len () != 1 { panic ! ("Expected exactly one subgraph in the Hydroflow IR") ; } let flat_graph = self . hydroflow_ir . remove (& 0) . unwrap () ; let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; (None , Some (tokens)) } } pub use crate :: HfBuiltWithId ; # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfBuiltWithId < 'a > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfBuiltWithId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (self . tokens)) } }
[INFO] [stdout]   |
[INFO] [stdout] help: ...otherwise replace it with an invocation of macro `deref`
[INFO] [stdout]   |
[INFO] [stdout] 1 - pub use std :: collections :: BTreeMap ; pub use std :: marker :: PhantomData ; pub use hydroflow :: scheduled :: context :: Context ; pub use hydroflow :: scheduled :: graph :: Hydroflow ; pub use hydroflow :: * ; pub use lang :: graph :: { partition_graph , HydroflowGraph } ; pub use proc_macro2 :: TokenStream ; pub use quote :: quote ; pub use stageleft :: runtime_support :: FreeVariable ; pub use stageleft :: Quoted ; pub mod runtime_support { pub use bincode ; } pub mod stream { pub use std :: cell :: RefCell ; pub use std :: hash :: Hash ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow :: bytes :: Bytes ; pub use hydroflow :: futures :: Sink ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: quote ; pub use serde :: de :: DeserializeOwned ; pub use serde :: Serialize ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use syn :: parse_quote ; pub use crate :: builder :: { ClusterIds , FlowLeaves } ; pub use crate :: cycle :: { CycleCollection , CycleComplete } ; pub use crate :: ir :: { DebugInstantiate , HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { CanSend , Location , LocationId } ; pub use crate :: { Cluster , Optional , Singleton } ; pub use crate :: stream :: Unbounded ; pub use crate :: stream :: Bounded ; pub use crate :: stream :: NoTick ; pub use crate :: stream :: Tick ; pub use crate :: stream :: Stream ; # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Stream { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Stream < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Stream { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , C , N > > ,) -> Stream < 'a , (T , O) , W , C , N > where O : Clone , { let other : Optional < 'a , O , Bounded , C , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn cross_product < O > (self , other : Stream < 'a , O , W , C , N >) -> Stream < 'a , (T , O) , W , C , N > where T : Clone , O : Clone , { if self . location_kind != other . location_kind { panic ! ("cross_product must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossProduct (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn union (self , other : Stream < 'a , T , W , C , N >) -> Stream < 'a , T , W , C , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn dest_sink < S : Unpin + Sink < T > + 'a > (self , sink : impl Quoted < 'a , S >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: DestSink { sink : sink . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn first (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } # [doc = " Allow this stream through if the other stream has elements, otherwise the output is empty."] pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } # [doc = " Allow this stream through if the other stream is empty, otherwise the output is empty."] pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn enumerate (self) -> Stream < 'a , (usize , T) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Enumerate (Box :: new (self . ir_node . into_inner ())) ,) } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn sort (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Ord , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Sort (Box :: new (self . ir_node . into_inner ())) ,) } pub fn count (self) -> Singleton < 'a , usize , Bounded , Tick , N > { self . fold (q ! (|| 0usize) , q ! (| count , _ | * count += 1)) } pub fn delta (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } pub fn unique (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Eq + Hash , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unique (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn tick_batch (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_prefix (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { self . tick_batch () . persist () } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn for_each < F : Fn (T) + 'a > (self , f : impl IntoQuotedMut < 'a , F >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: ForEach { input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , f : f . splice () . into () , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Unbounded , NoTick , N > { pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . tick_batch () . continue_if (samples . first ()) . all_ticks () } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Unbounded , NoTick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , C , N : Location > Stream < 'a , T , Bounded , C , N > { pub fn filter_not_in (self , other : Stream < 'a , T , Bounded , C , N >) -> Stream < 'a , T , Bounded , C , N > where T : Eq + Hash , { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Difference (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Stream < 'a , & T , W , C , N > { pub fn cloned (self) -> Stream < 'a , T , W , C , N > { self . map (q ! (| d | d . clone ())) } } # [cfg (stageleft_macro)] impl < 'a , K , V1 , W , C , N : Location > Stream < 'a , (K , V1) , W , C , N > { pub fn join < W2 , V2 > (self , n : Stream < 'a , (K , V2) , W2 , C , N > ,) -> Stream < 'a , (K , (V1 , V2)) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Join (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } pub fn anti_join < W2 > (self , n : Stream < 'a , K , W2 , C , N >) -> Stream < 'a , (K , V1) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("anti_join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: AntiJoin (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , K : Eq + Hash , V , N : Location > Stream < 'a , (K , V) , Bounded , Tick , N > { pub fn fold_keyed < A , I : Fn () -> A + 'a , F : Fn (& mut A , V) + 'a > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , A) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FoldKeyed { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce_keyed < F : Fn (& mut V , V) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , V) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: ReduceKeyed { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } pub fn get_this_crate () -> TokenStream { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , Span :: call_site ()) ; quote ! { # ident } } } } pub fn serialize_bincode < T : Serialize > (is_demux : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if is_demux { parse_quote ! { map (| (id , data) | { (id , # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into ()) }) } } else { parse_quote ! { map (| data | { # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into () }) } } } pub fn deserialize_bincode < T : DeserializeOwned > (tagged : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if tagged { parse_quote ! { map (| res | { let (id , b) = res . unwrap () ; (id , # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& b) . unwrap ()) }) } } else { parse_quote ! { map (| res | { # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& res . unwrap ()) . unwrap () }) } } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn send_bincode < N2 : Location , CoreType > (self , other : & N2 ,) -> Stream < 'a , N :: Out < CoreType > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T > , CoreType : Serialize + DeserializeOwned , { let serialize_pipeline = Some (serialize_bincode :: < CoreType > (N :: is_demux ())) ; let deserialize_pipeline = Some (deserialize_bincode :: < CoreType > (N :: is_tagged ())) ; Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bytes < N2 : Location > (self , other : & N2 ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T > , { Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline : None , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline : if N :: is_tagged () { Some (parse_quote ! (map (| (id , b) | (id , b . unwrap () . freeze ())))) } else { Some (parse_quote ! (map (| b | b . unwrap () . freeze ()))) } , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bincode_interleaved < N2 : Location , Tag , CoreType > (self , other : & N2 ,) -> Stream < 'a , CoreType , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T , Out < CoreType > = (Tag , CoreType) > , CoreType : Serialize + DeserializeOwned , { self . send_bincode :: < N2 , CoreType > (other) . map (q ! (| (_ , b) | b)) } pub fn send_bytes_interleaved < N2 : Location , Tag > (self , other : & N2 ,) -> Stream < 'a , Bytes , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T , Out < Bytes > = (Tag , Bytes) > , { self . send_bytes :: < N2 > (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bincode < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < T > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) > , T : Clone + Serialize + DeserializeOwned , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bincode (other) } pub fn broadcast_bincode_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , T , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) , Out < T > = (Tag , T) > + 'a , T : Clone + Serialize + DeserializeOwned , { self . broadcast_bincode (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bytes < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) > + 'a , T : Clone , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bytes (other) } pub fn broadcast_bytes_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , Bytes , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) , Out < Bytes > = (Tag , Bytes) > + 'a , T : Clone , { self . broadcast_bytes (other) . map (q ! (| (_ , b) | b)) } } } pub use stream :: { Bounded , NoTick , Stream , Tick , Unbounded } ; pub mod singleton { pub use std :: cell :: RefCell ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use crate :: builder :: FlowLeaves ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial , CycleComplete } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: Stream ; pub use crate :: singleton :: CrossResult ; # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Singleton < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Singleton :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } pub use crate :: singleton :: Singleton ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Singleton { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleComplete < 'a > for Singleton < 'a , T , Bounded , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleCollectionWithInitial < 'a > for Singleton < 'a , T , Bounded , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , initial : Self , l : LocationId ,) -> Self { Singleton :: new (l , ir_leaves , HfPlusNode :: Union (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , }) , initial . ir_node . into_inner () . into () ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Singleton < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Singleton { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , U , W , C , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (Self :: other_ir_node (other)) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Singleton < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CrossSingleton (Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , Box :: new (HfPlusNode :: Unpersist (Box :: new (Self :: other_ir_node (other)))) ,))) ,) } } pub use crate :: singleton :: Optional ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Optional { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } pub fn some (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: new (singleton . location_kind , singleton . ir_leaves , singleton . ir_node . into_inner () ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > From < Singleton < 'a , T , W , C , N > > for Optional < 'a , T , W , C , N > { fn from (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: some (singleton) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Optional < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Optional { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn into_stream (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , Tick , N > > ,) -> Optional < 'a , (T , O) , Bounded , Tick , N > where O : Clone , { let other : Optional < 'a , O , Bounded , Tick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn union (self , other : Optional < 'a , T , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Optional < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_samples (self) -> Stream < 'a , T , Unbounded , NoTick , N > { self . latest_tick () . all_ticks () } pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . latest_tick () . continue_if (samples . first ()) . latest () . tick_samples () } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Unbounded , NoTick , N > > ,) -> Optional < 'a , (T , O) , Unbounded , NoTick , N > where O : Clone , { let other : Optional < 'a , O , Unbounded , NoTick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } self . latest_tick () . cross_singleton (other . latest_tick ()) . latest () } } } pub use singleton :: { Optional , Singleton } ; pub mod location { pub use std :: marker :: PhantomData ; pub use crate :: location :: LocationId ; pub use crate :: location :: Location ; pub use crate :: location :: Process ; # [cfg (stageleft_macro)] impl < P > Clone for Process < P > { fn clone (& self) -> Self { Process { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < P > Location for Process < P > { fn id (& self) -> LocationId { LocationId :: Process (self . id) } } pub use crate :: location :: Cluster ; # [cfg (stageleft_macro)] impl < C > Clone for Cluster < C > { fn clone (& self) -> Self { Cluster { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < C > Location for Cluster < C > { fn id (& self) -> LocationId { LocationId :: Cluster (self . id) } } pub use crate :: location :: CanSend ; # [cfg (stageleft_macro)] impl < P1 , P2 > CanSend < Process < P2 > > for Process < P1 > { type In < T > = T ; type Out < T > = T ; fn is_demux () -> bool { false } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < P1 , C2 > CanSend < Cluster < C2 > > for Process < P1 > { type In < T > = (u32 , T) ; type Out < T > = T ; fn is_demux () -> bool { true } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < C1 , P2 > CanSend < Process < P2 > > for Cluster < C1 > { type In < T > = T ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { false } fn is_tagged () -> bool { true } } # [cfg (stageleft_macro)] impl < C1 , C2 > CanSend < Cluster < C2 > > for Cluster < C1 > { type In < T > = (u32 , T) ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { true } fn is_tagged () -> bool { true } } } pub use location :: { Cluster , Process } ; pub mod deploy { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use stageleft :: Quoted ; pub mod graphs { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use super :: { LocalDeploy , Node , ProcessSpec } ; pub use crate :: deploy :: graphs :: SingleProcessGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for SingleProcessGraph { type Process = SingleNode ; type Cluster = SingleNode ; type Meta = () ; type GraphId = () ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { SingleNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { SingleNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , SingleProcessGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> SingleNode { SingleNode { } } } pub use crate :: deploy :: graphs :: SingleNode ; # [cfg (stageleft_macro)] impl Node for SingleNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } pub use crate :: deploy :: graphs :: MultiGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for MultiGraph { type Process = MultiNode ; type Cluster = MultiNode ; type Meta = () ; type GraphId = usize ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { MultiNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { MultiNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , MultiGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> MultiNode { MultiNode { } } } pub use crate :: deploy :: graphs :: MultiNode ; # [cfg (stageleft_macro)] impl Node for MultiNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } } pub use graphs :: * ; pub use crate :: deploy :: LocalDeploy ; pub use crate :: deploy :: Deploy ; # [cfg (stageleft_macro)] impl < 'a , T : Deploy < 'a , Process = N , Cluster = C , Meta = M , GraphId = R > , N : Node < Meta = M > , C : Node < Meta = M > , M : Default , R , > LocalDeploy < 'a > for T { type Process = N ; type Cluster = C ; type Meta = M ; type GraphId = R ; fn has_trivial_node () -> bool { < T as Deploy < 'a > > :: has_trivial_node () } fn trivial_process (id : usize) -> Self :: Process { < T as Deploy < 'a > > :: trivial_process (id) } fn trivial_cluster (id : usize) -> Self :: Cluster { < T as Deploy < 'a > > :: trivail_cluster (id) } } pub use crate :: deploy :: ProcessSpec ; pub use crate :: deploy :: ClusterSpec ; pub use crate :: deploy :: Node ; } pub use deploy :: { ClusterSpec , Deploy , ProcessSpec } ; pub mod cycle { pub use std :: marker :: PhantomData ; pub use crate :: builder :: FlowLeaves ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: cycle :: CycleComplete ; pub use crate :: cycle :: CycleCollection ; pub use crate :: cycle :: CycleCollectionWithInitial ; pub use crate :: cycle :: HfCycle ; # [cfg (stageleft_macro)] impl < 'a , S : CycleComplete < 'a > > HfCycle < 'a , S > { pub fn complete (self , stream : S) { let ident = self . ident ; S :: complete (stream , ident) } } } pub use cycle :: HfCycle ; pub mod builder { pub use std :: cell :: RefCell ; pub use std :: collections :: HashMap ; pub use std :: marker :: PhantomData ; pub use std :: rc :: Rc ; pub use std :: time :: Duration ; pub use hydroflow :: futures :: stream :: Stream as FuturesStream ; pub use hydroflow :: { tokio , tokio_stream } ; pub use internal :: TokenStream ; pub use proc_macro2 :: Span ; pub use quote :: quote ; pub use runtime_support :: FreeVariable ; pub use stageleft :: * ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Cluster , Location , LocationId , Process } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: { HfCycle , Optional , RuntimeContext , Singleton , Stream } ; pub mod built { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use hydroflow_lang :: graph :: { eliminate_extra_unions_tees , HydroflowGraph } ; pub use super :: deploy :: { DeployFlow , DeployResult } ; pub use crate :: deploy :: { ClusterSpec , Deploy , LocalDeploy , ProcessSpec } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Cluster , Process } ; pub use crate :: HfCompiled ; pub use crate :: builder :: built :: BuiltFlow ; # [cfg (stageleft_macro)] impl < 'a > Drop for BuiltFlow < 'a > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped BuiltFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn ir (& self) -> & Vec < HfPlusLeaf < 'a > > { & self . ir } pub fn optimize_with (mut self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> BuiltFlow < 'a > { self . used = true ; BuiltFlow { ir : f (std :: mem :: take (& mut self . ir)) , processes : std :: mem :: take (& mut self . processes) , clusters : std :: mem :: take (& mut self . clusters) , used : false , _phantom : PhantomData , } } } pub fn build_inner (ir : & mut Vec < HfPlusLeaf >) -> BTreeMap < usize , HydroflowGraph > { let mut builders = BTreeMap :: new () ; let mut built_tees = HashMap :: new () ; let mut next_stmt_id = 0 ; for leaf in ir { leaf . emit (& mut builders , & mut built_tees , & mut next_stmt_id) ; } builders . into_iter () . map (| (k , v) | { let (mut flat_graph , _ , _) = v . build () ; eliminate_extra_unions_tees (& mut flat_graph) ; (k , flat_graph) }) . collect () } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn compile_no_network < D : LocalDeploy < 'a > > (mut self) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; HfCompiled { hydroflow_ir : build_inner (& mut self . ir) , extra_stmts : BTreeMap :: new () , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> BuiltFlow < 'a > { self . optimize_with (crate :: persist_pullup :: persist_pullup) } fn into_deploy < D : LocalDeploy < 'a > > (mut self) -> DeployFlow < 'a , D > { self . used = true ; let processes = if D :: has_trivial_node () { self . processes . iter () . map (| id | (* id , D :: trivial_process (* id))) . collect () } else { HashMap :: new () } ; let clusters = if D :: has_trivial_node () { self . clusters . iter () . map (| id | (* id , D :: trivial_cluster (* id))) . collect () } else { HashMap :: new () } ; DeployFlow { ir : std :: mem :: take (& mut self . ir) , nodes : processes , clusters , used : false , _phantom : PhantomData , } } pub fn with_process < P , D : LocalDeploy < 'a > > (self , process : & Process < P > , spec : impl ProcessSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_process (process , spec) } pub fn with_cluster < C , D : LocalDeploy < 'a > > (self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_cluster (cluster , spec) } pub fn compile < D : Deploy < 'a > + 'a > (self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . into_deploy :: < D > () . compile (env) } pub fn deploy < D : Deploy < 'a , CompileEnv = () > + 'a > (self , env : & mut D :: InstantiateEnv ,) -> DeployResult < 'a , D > { self . into_deploy :: < D > () . deploy (env) } } } pub mod deploy { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use proc_macro2 :: Span ; pub use stageleft :: Quoted ; pub use super :: built :: build_inner ; pub use crate :: deploy :: { LocalDeploy , Node } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: { Cluster , ClusterSpec , Deploy , HfCompiled , Process , ProcessSpec } ; pub use crate :: builder :: deploy :: DeployFlow ; # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > Drop for DeployFlow < 'a , D > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped DeployFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > DeployFlow < 'a , D > { pub fn with_process < P > (mut self , process : & Process < P > , spec : impl ProcessSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < P > () . to_string () ; self . nodes . insert (process . id , spec . build (process . id , & tag_name)) ; self } pub fn with_cluster < C > (mut self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < C > () . to_string () ; self . clusters . insert (cluster . id , spec . build (cluster . id , & tag_name)) ; self } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployFlow < 'a , D > { pub fn compile (mut self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; let mut seen_tees : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | leaf . compile_network :: < D > (env , & mut seen_tees , & self . nodes , & self . clusters)) . collect () ; let extra_stmts = self . extra_stmts (env) ; HfCompiled { hydroflow_ir : build_inner (& mut ir_leaves_networked) , extra_stmts , _phantom : PhantomData , } } fn extra_stmts (& self , env : & < D as Deploy < 'a > > :: CompileEnv) -> BTreeMap < usize , Vec < syn :: Stmt > > { let all_locations_count = self . nodes . len () + self . clusters . len () ; let mut extra_stmts : BTreeMap < usize , Vec < syn :: Stmt > > = BTreeMap :: new () ; for & c_id in self . clusters . keys () { let self_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , c_id) , Span :: call_site () ,) ; let self_id_expr = D :: cluster_self_id (env) . splice () ; extra_stmts . entry (c_id) . or_default () . push (syn :: parse_quote ! { let # self_id_ident = # self_id_expr ; }) ; for other_location in 0 .. all_locations_count { let other_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , c_id) , Span :: call_site () ,) ; let other_id_expr = D :: cluster_ids (env , c_id) . splice () ; extra_stmts . entry (other_location) . or_default () . push (syn :: parse_quote ! { let # other_id_ident = # other_id_expr ; }) ; } } extra_stmts } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a , CompileEnv = () > > DeployFlow < 'a , D > { # [must_use] pub fn deploy (mut self , env : & mut D :: InstantiateEnv) -> DeployResult < 'a , D > { self . used = true ; let mut seen_tees_instantiate : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | { leaf . compile_network :: < D > (& () , & mut seen_tees_instantiate , & self . nodes , & self . clusters ,) }) . collect () ; let mut compiled = build_inner (& mut ir_leaves_networked) ; let mut extra_stmts = self . extra_stmts (& ()) ; let mut meta = D :: Meta :: default () ; let (mut processes , mut clusters) = (std :: mem :: take (& mut self . nodes) . into_iter () . map (| (node_id , node) | { node . instantiate (env , & mut meta , compiled . remove (& node_id) . unwrap () , extra_stmts . remove (& node_id) . unwrap_or_default () ,) ; (node_id , node) }) . collect :: < HashMap < _ , _ > > () , std :: mem :: take (& mut self . clusters) . into_iter () . map (| (cluster_id , cluster) | { cluster . instantiate (env , & mut meta , compiled . remove (& cluster_id) . unwrap () , extra_stmts . remove (& cluster_id) . unwrap_or_default () ,) ; (cluster_id , cluster) }) . collect :: < HashMap < _ , _ > > () ,) ; for node in processes . values_mut () { node . update_meta (& meta) ; } for cluster in clusters . values_mut () { cluster . update_meta (& meta) ; } let mut seen_tees_connect = HashMap :: new () ; for leaf in ir_leaves_networked { leaf . connect_network (& mut seen_tees_connect) ; } DeployResult { processes , clusters , } } } pub use crate :: builder :: deploy :: DeployResult ; # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployResult < 'a , D > { pub fn get_process < P > (& self , p : & Process < P >) -> & D :: Process { let id = match p . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . processes . get (& id) . unwrap () } pub fn get_cluster < C > (& self , c : & Cluster < C >) -> & D :: Cluster { let id = match c . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . clusters . get (& id) . unwrap () } } } # [doc = " Tracks the leaves of the dataflow IR. This is referenced by"] # [doc = " `Stream` and `HfCycle` to build the IR. The inner option will"] # [doc = " be set to `None` when this builder is finalized."] pub type FlowLeaves < 'a > = Rc < RefCell < Option < Vec < HfPlusLeaf < 'a > > > > > ; pub use crate :: builder :: ClusterIds ; # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Vec < u32 > > for ClusterIds < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , & 'a Vec < u32 > > for ClusterIds < 'a > { } # [derive (Copy , Clone)] pub struct ClusterSelfId < 'a > { pub id : usize , pub _phantom : PhantomData < & 'a mut & 'a u32 > , } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < u32 > for ClusterSelfId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , u32 > for ClusterSelfId < 'a > { } pub use crate :: builder :: FlowBuilder ; # [cfg (stageleft_macro)] impl < 'a > Drop for FlowBuilder < 'a > { fn drop (& mut self) { if ! self . finalized { panic ! ("Dropped FlowBuilder without finalizing, you may have forgotten to call `with_default_optimize`, `optimize_with`, or `finalize`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > QuotedContext for FlowBuilder < 'a > { fn create () -> Self { FlowBuilder :: new () } } # [cfg (stageleft_macro)] impl < 'a > FlowBuilder < 'a > { # [allow (clippy :: new_without_default)] pub fn new () -> FlowBuilder < 'a > { FlowBuilder { ir_leaves : Rc :: new (RefCell :: new (Some (Vec :: new ()))) , nodes : RefCell :: new (vec ! []) , clusters : RefCell :: new (vec ! []) , cycle_ids : RefCell :: new (HashMap :: new ()) , next_node_id : RefCell :: new (0) , finalized : false , _phantom : PhantomData , } } pub fn finalize (mut self) -> built :: BuiltFlow < 'a > { self . finalized = true ; built :: BuiltFlow { ir : self . ir_leaves . borrow_mut () . take () . unwrap () , processes : self . nodes . replace (vec ! []) , clusters : self . clusters . replace (vec ! []) , used : false , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> built :: BuiltFlow < 'a > { self . finalize () . with_default_optimize () } pub fn optimize_with (self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> built :: BuiltFlow < 'a > { self . finalize () . optimize_with (f) } pub fn ir_leaves (& self) -> & FlowLeaves < 'a > { & self . ir_leaves } pub fn process < P > (& self) -> Process < P > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . nodes . borrow_mut () . push (id) ; Process { id , _phantom : PhantomData , } } pub fn cluster < C > (& self) -> Cluster < C > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . clusters . borrow_mut () . push (id) ; Cluster { id , _phantom : PhantomData , } } pub fn runtime_context (& self) -> RuntimeContext < 'a > { RuntimeContext { _phantom : PhantomData , } } pub fn cluster_members < C > (& self , cluster : & Cluster < C > ,) -> impl Quoted < 'a , & 'a Vec < u32 > > + Copy + 'a { ClusterIds { id : cluster . id , _phantom : PhantomData , } } pub fn cluster_self_id < C > (& self , cluster : & Cluster < C >) -> impl Quoted < 'a , u32 > + Copy + 'a { ClusterSelfId { id : cluster . id , _phantom : PhantomData , } } pub fn spin < L : Location > (& self , on : & L) -> Stream < 'a , () , Unbounded , NoTick , L > { Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Spin () , location_kind : on . id () , })) ,) } pub fn spin_batch < L : Location > (& self , on : & L , batch_size : impl Quoted < 'a , usize > + Copy + 'a ,) -> Stream < 'a , () , Bounded , Tick , L > { self . spin (on) . flat_map (q ! (move | _ | 0 .. batch_size)) . map (q ! (| _ | ())) . tick_batch () } pub fn source_stream < T , E : FuturesStream < Item = T > + Unpin , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Unbounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Stream (e . into ()) , location_kind : on . id () , })) ,) } pub fn source_iter < T , E : IntoIterator < Item = T > , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Bounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , })) ,) } pub fn singleton < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Singleton < 'a , T , Bounded , NoTick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Singleton :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,)))) ,) } pub fn singleton_first_tick < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Optional < 'a , T , Bounded , Tick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,) } pub fn source_interval < L : Location > (& self , on : & L , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , () , Unbounded , NoTick , L > { let interval = interval . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : on . id () , })) ,) } pub fn source_interval_delayed < L : Location > (& self , on : & L , delay : impl Quoted < 'a , Duration > + Copy + 'a , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , tokio :: time :: Instant , Unbounded , NoTick , L > { self . source_stream (on , q ! (tokio_stream :: wrappers :: IntervalStream :: new (tokio :: time :: interval_at (tokio :: time :: Instant :: now () + delay , interval))) ,) . tick_batch () . first () . latest () } pub fn cycle < S : CycleCollection < 'a > > (& self , on : & S :: Location) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , on . id ()) ,) } pub fn cycle_with_initial < S : CycleCollectionWithInitial < 'a > > (& self , on : & S :: Location , initial : S ,) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , initial , on . id ()) ,) } } } pub use builder :: FlowBuilder ; pub mod ir { pub use core :: panic ; pub use std :: cell :: RefCell ; pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow_lang :: graph :: FlatGraphBuilder ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: ToTokens ; pub use syn :: parse_quote ; pub use crate :: deploy :: Deploy ; pub use crate :: location :: LocationId ; pub use crate :: ir :: DebugExpr ; # [cfg (stageleft_macro)] impl From < syn :: Expr > for DebugExpr { fn from (expr : syn :: Expr) -> DebugExpr { DebugExpr (expr) } } # [cfg (stageleft_macro)] impl Deref for DebugExpr { type Target = syn :: Expr ; fn deref (& self) -> & Self :: Target { & self . 0 } } # [cfg (stageleft_macro)] impl ToTokens for DebugExpr { fn to_tokens (& self , tokens : & mut TokenStream) { self . 0 . to_tokens (tokens) ; } } # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugExpr { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "{}" , self . 0 . to_token_stream ()) } } pub use crate :: ir :: DebugInstantiate ; # [cfg (stageleft_macro)] impl < 'a > std :: fmt :: Debug for DebugInstantiate < 'a > { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<network instantiate>") } } pub use crate :: ir :: DebugPipelineFn ; # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugPipelineFn { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<function>") } } pub use crate :: ir :: HfPlusSource ; pub use crate :: ir :: HfPlusLeaf ; # [cfg (stageleft_macro)] impl < 'a > HfPlusLeaf < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . compile_network :: < D > (compile_env , s , nodes , clusters) ; } , seen_tees ,) } pub fn connect_network (self , seen_tees : & mut SeenTees < 'a >) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . connect_network (s) ; } , seen_tees ,) } pub fn transform_children (self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) -> HfPlusLeaf < 'a > { match self { HfPlusLeaf :: ForEach { f , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: ForEach { f , input } } HfPlusLeaf :: DestSink { sink , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: DestSink { sink , input } } HfPlusLeaf :: CycleSink { ident , location_kind , mut input , } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: CycleSink { ident , location_kind , input , } } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) { match self { HfPlusLeaf :: ForEach { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> for_each (# f) ; }) ; } HfPlusLeaf :: DestSink { sink , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink) ; }) ; } HfPlusLeaf :: CycleSink { ident , location_kind , input , } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; assert_eq ! (input_location_id , * location_id , "cycle_sink location mismatch") ; graph_builders . entry (* location_id) . or_default () . add_statement (parse_quote ! { # ident = # input_ident ; }) ; } } } } pub use crate :: ir :: HfPlusNode ; pub type SeenTees < 'a > = HashMap < * const RefCell < HfPlusNode < 'a > > , Rc < RefCell < HfPlusNode < 'a > > > > ; # [cfg (stageleft_macro)] impl < 'a > HfPlusNode < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (& mut self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) { self . transform_children (| n , s | n . compile_network :: < D > (compile_env , s , nodes , clusters) , seen_tees ,) ; if let HfPlusNode :: Network { from_location , to_location , instantiate_fn , .. } = self { let (sink_expr , source_expr , connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { let ((sink , source) , connect_fn) = match (from_location , to_location) { (LocationId :: Process (from) , LocationId :: Process (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: o2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Process (from) , LocationId :: Cluster (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: o2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Process (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: m2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Cluster (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: m2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } } ; (sink , source , connect_fn) } DebugInstantiate :: Finalized (_ , _ , _) => panic ! ("network already finalized") , } ; * instantiate_fn = DebugInstantiate :: Finalized (sink_expr , source_expr , connect_fn) ; } } pub fn connect_network (& mut self , seen_tees : & mut SeenTees < 'a >) { self . transform_children (| n , s | n . connect_network (s) , seen_tees) ; if let HfPlusNode :: Network { instantiate_fn , .. } = self { match instantiate_fn { DebugInstantiate :: Building () => panic ! ("network not built") , DebugInstantiate :: Finalized (_ , _ , ref connect_fn) => { connect_fn () ; } } } } pub fn transform_children (& mut self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) { match self { HfPlusNode :: Placeholder => { panic ! () ; } HfPlusNode :: Source { .. } => { } HfPlusNode :: CycleSource { .. } => { } HfPlusNode :: Tee { inner } => { if let Some (transformed) = seen_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { * inner = transformed . clone () ; } else { let transformed_cell = Rc :: new (RefCell :: new (HfPlusNode :: Placeholder)) ; seen_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , transformed_cell . clone () ,) ; let mut orig = inner . replace (HfPlusNode :: Placeholder) ; transform (& mut orig , seen_tees) ; * transformed_cell . borrow_mut () = orig ; * inner = transformed_cell ; } } HfPlusNode :: Persist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Unpersist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Delta (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Union (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossProduct (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossSingleton (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Join (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Difference (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: AntiJoin (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Map { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FlatMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Filter { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FilterMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Sort (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: DeferTick (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Enumerate (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Inspect { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Unique (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Fold { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FoldKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Reduce { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: ReduceKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Network { input , .. } => { transform (input . as_mut () , seen_tees) ; } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) -> (syn :: Ident , usize) { match self { HfPlusNode :: Placeholder => { panic ! () } HfPlusNode :: Persist (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let persist_id = * next_stmt_id ; * next_stmt_id += 1 ; let persist_ident = syn :: Ident :: new (& format ! ("stream_{}" , persist_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # persist_ident = # inner_ident -> persist ::<'static > () ; }) ; (persist_ident , location) } HfPlusNode :: Unpersist (_) => { panic ! ("Unpersist is a marker node and should have been optimized away. This is likely a compiler bug.") } HfPlusNode :: Delta (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let delta_id = * next_stmt_id ; * next_stmt_id += 1 ; let delta_ident = syn :: Ident :: new (& format ! ("stream_{}" , delta_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # delta_ident = # inner_ident -> multiset_delta () ; }) ; (delta_ident , location) } HfPlusNode :: Source { source , location_kind , } => { let source_id = * next_stmt_id ; * next_stmt_id += 1 ; let source_ident = syn :: Ident :: new (& format ! ("stream_{}" , source_id) , Span :: call_site ()) ; let source_stmt = match source { HfPlusSource :: Stream (expr) => { parse_quote ! { # source_ident = source_stream (# expr) ; } } HfPlusSource :: Iter (expr) => { parse_quote ! { # source_ident = source_iter (# expr) ; } } HfPlusSource :: Interval (expr) => { parse_quote ! { # source_ident = source_interval (# expr) ; } } HfPlusSource :: Spin () => { parse_quote ! { # source_ident = spin () ; } } } ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; graph_builders . entry (* location_id) . or_default () . add_statement (source_stmt) ; (source_ident , * location_id) } HfPlusNode :: CycleSource { ident , location_kind , } => { let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; (ident . clone () , * location_id) } HfPlusNode :: Tee { inner } => { if let Some (ret) = built_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { ret . clone () } else { let (inner_ident , inner_location_id) = inner . borrow () . emit (graph_builders , built_tees , next_stmt_id) ; let tee_id = * next_stmt_id ; * next_stmt_id += 1 ; let tee_ident = syn :: Ident :: new (& format ! ("stream_{}" , tee_id) , Span :: call_site ()) ; let builder = graph_builders . entry (inner_location_id) . or_default () ; builder . add_statement (parse_quote ! { # tee_ident = # inner_ident -> tee () ; }) ; built_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , (tee_ident . clone () , inner_location_id) ,) ; (tee_ident , inner_location_id) } } HfPlusNode :: Union (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "union inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let union_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # union_ident = union () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [0] # union_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # union_ident ; }) ; (union_ident , left_location_id) } HfPlusNode :: CrossSingleton (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "cross_singleton inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let cross_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # cross_ident = cross_singleton () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [input] # cross_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [single] # cross_ident ; }) ; (cross_ident , left_location_id) } HfPlusNode :: CrossProduct (..) | HfPlusNode :: Join (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: CrossProduct (..)) { parse_quote ! (cross_join_multiset) } else { parse_quote ! (join_multiset) } ; let (HfPlusNode :: CrossProduct (left , right) | HfPlusNode :: Join (left , right)) = self else { unreachable ! () } ; let (left_inner , left_was_persist) = if let HfPlusNode :: Persist (left) = left . as_ref () { (left , true) } else { (left , false) } ; let (right_inner , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left_inner . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right_inner . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "join / cross product inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; match (left_was_persist , right_was_persist) { (true , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'static > () ; }) ; } (true , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'tick > () ; }) ; } (false , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } (false , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } } ; builder . add_statement (parse_quote ! { # left_ident -> [0] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Difference (..) | HfPlusNode :: AntiJoin (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Difference (..)) { parse_quote ! (difference_multiset) } else { parse_quote ! (anti_join_multiset) } ; let (HfPlusNode :: Difference (left , right) | HfPlusNode :: AntiJoin (left , right)) = self else { unreachable ! () } ; let (right , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "difference / anti join inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; if right_was_persist { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } else { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } builder . add_statement (parse_quote ! { # left_ident -> [pos] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [neg] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Map { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let map_id = * next_stmt_id ; * next_stmt_id += 1 ; let map_ident = syn :: Ident :: new (& format ! ("stream_{}" , map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # map_ident = # input_ident -> map (# f) ; }) ; (map_ident , input_location_id) } HfPlusNode :: FlatMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let flat_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let flat_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , flat_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # flat_map_ident = # input_ident -> flat_map (# f) ; }) ; (flat_map_ident , input_location_id) } HfPlusNode :: Filter { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_ident = # input_ident -> filter (# f) ; }) ; (filter_ident , input_location_id) } HfPlusNode :: FilterMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_map_ident = # input_ident -> filter_map (# f) ; }) ; (filter_map_ident , input_location_id) } HfPlusNode :: Sort (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sort_id = * next_stmt_id ; * next_stmt_id += 1 ; let sort_ident = syn :: Ident :: new (& format ! ("stream_{}" , sort_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # sort_ident = # input_ident -> sort () ; }) ; (sort_ident , input_location_id) } HfPlusNode :: DeferTick (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let defer_tick_id = * next_stmt_id ; * next_stmt_id += 1 ; let defer_tick_ident = syn :: Ident :: new (& format ! ("stream_{}" , defer_tick_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # defer_tick_ident = # input_ident -> defer_tick_lazy () ; }) ; (defer_tick_ident , input_location_id) } HfPlusNode :: Enumerate (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let enumerate_id = * next_stmt_id ; * next_stmt_id += 1 ; let enumerate_ident = syn :: Ident :: new (& format ! ("stream_{}" , enumerate_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # enumerate_ident = # input_ident -> enumerate () ; }) ; (enumerate_ident , input_location_id) } HfPlusNode :: Inspect { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let inspect_id = * next_stmt_id ; * next_stmt_id += 1 ; let inspect_ident = syn :: Ident :: new (& format ! ("stream_{}" , inspect_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # inspect_ident = # input_ident -> inspect (# f) ; }) ; (inspect_ident , input_location_id) } HfPlusNode :: Unique (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let unique_id = * next_stmt_id ; * next_stmt_id += 1 ; let unique_ident = syn :: Ident :: new (& format ! ("stream_{}" , unique_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # unique_ident = # input_ident -> unique ::<'tick > () ; }) ; (unique_ident , input_location_id) } HfPlusNode :: Fold { .. } | HfPlusNode :: FoldKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Fold { .. }) { parse_quote ! (fold) } else { parse_quote ! (fold_keyed) } ; let (HfPlusNode :: Fold { init , acc , input } | HfPlusNode :: FoldKeyed { init , acc , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let fold_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'static > (# init , # acc) ; }) ; } else { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'tick > (# init , # acc) ; }) ; } (fold_ident , input_location_id) } HfPlusNode :: Reduce { .. } | HfPlusNode :: ReduceKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Reduce { .. }) { parse_quote ! (reduce) } else { parse_quote ! (reduce_keyed) } ; let (HfPlusNode :: Reduce { f , input } | HfPlusNode :: ReduceKeyed { f , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let reduce_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'static > (# f) ; }) ; } else { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'tick > (# f) ; }) ; } (reduce_ident , input_location_id) } HfPlusNode :: Network { from_location : _ , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input , } => { let (sink_expr , source_expr , _connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { panic ! ("Expected the network to be finalized") } DebugInstantiate :: Finalized (sink , source , connect_fn) => { (sink , source , connect_fn) } } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sender_builder = graph_builders . entry (input_location_id) . or_default () ; if let Some (serialize_pipeline) = serialize_pipeline { sender_builder . add_statement (parse_quote ! { # input_ident -> # serialize_pipeline -> dest_sink (# sink_expr) ; }) ; } else { sender_builder . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink_expr) ; }) ; } let to_id = match to_location { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let receiver_builder = graph_builders . entry (* to_id) . or_default () ; let receiver_stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let receiver_stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , receiver_stream_id) , Span :: call_site ()) ; if let Some (deserialize_pipeline) = deserialize_pipeline { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) -> # deserialize_pipeline ; }) ; } else { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) ; }) ; } (receiver_stream_ident , * to_id) } } } } } pub mod persist_pullup { pub use std :: cell :: RefCell ; pub use std :: collections :: HashSet ; pub use std :: ops :: Deref ; pub use crate :: ir :: * ; pub fn persist_pullup_node < 'a > (node : & mut HfPlusNode < 'a > , seen_tees : & mut SeenTees < 'a > , persist_pulled_tees : & mut HashSet < * const RefCell < HfPlusNode < 'a > > > ,) { node . transform_children (| n , s | persist_pullup_node (n , s , persist_pulled_tees) , seen_tees ,) ; match node { HfPlusNode :: Unpersist (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Unpersist (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Delta (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Delta (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Tee { inner } => { if persist_pulled_tees . contains (& (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >)) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } else { let inner_borrow = inner . borrow () ; if let HfPlusNode :: Persist (_) = inner_borrow . deref () { drop (inner_borrow) ; persist_pulled_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >) ; if let HfPlusNode :: Persist (box behind_persist) = inner . replace (HfPlusNode :: Placeholder) { * inner . borrow_mut () = behind_persist ; } else { unreachable ! () } * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } } } HfPlusNode :: Map { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Map { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Map { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: FlatMap { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: FlatMap { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: FlatMap { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Filter { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Filter { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Filter { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Network { input : box HfPlusNode :: Persist (_) , .. } => { if let HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Union (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Union (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Union (left , right))) ; } else { unreachable ! () } } HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: CrossProduct (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,) ,)))) ; } else { unreachable ! () } } HfPlusNode :: Join (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Join (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: Join (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,))))) ; } else { unreachable ! () } } _ => { } } } pub fn persist_pullup (ir : Vec < HfPlusLeaf >) -> Vec < HfPlusLeaf > { let mut seen_tees = Default :: default () ; let mut persist_pulled_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| n , s | persist_pullup_node (n , s , & mut persist_pulled_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn persist_pullup_through_map () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } # [test] fn persist_pullup_behind_tee () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; let before_tee = flow . source_iter (& process , q ! (0 .. 10)) . tick_batch () . persist () ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } } } pub mod profiler { pub use std :: cell :: RefCell ; pub use hydroflow :: futures :: channel :: mpsc :: UnboundedSender ; pub use stageleft :: * ; pub use crate as hydroflow_plus ; pub use crate :: ir :: * ; pub use crate :: RuntimeContext ; pub fn increment_counter (count : & mut u64) { * count += 1 ; } pub fn quoted_any_fn < 'a , F : Fn (& usize) + 'a , Q : IntoQuotedMut < 'a , F > > (q : Q) -> Q { q } # [doc = " Add a profiling node before each node to count the cardinality of its input"] pub fn add_profiling_node < 'a > (node : & mut HfPlusNode < 'a > , _context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > , id : & mut u32 , seen_tees : & mut SeenTees < 'a > ,) { let my_id = * id ; * id += 1 ; node . transform_children (| node , seen_tees | { add_profiling_node (node , _context , counters , counter_queue , id , seen_tees) } , seen_tees ,) ; let orig_node = std :: mem :: replace (node , HfPlusNode :: Placeholder) ; * node = HfPlusNode :: Inspect { f : quoted_any_fn (q ! ({ counter_queue . borrow () . unbounded_send ((my_id as usize , counters . borrow () [my_id as usize])) . unwrap () ; counters . borrow_mut () [my_id as usize] = 0 ; move | _ | { hydroflow_plus :: profiler :: increment_counter (& mut counters . borrow_mut () [my_id as usize] ,) ; } })) . splice () . into () , input : Box :: new (orig_node) , } } # [doc = " Count the cardinality of each input and periodically output to a file"] pub fn profiling < 'a > (ir : Vec < HfPlusLeaf < 'a > > , context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > ,) -> Vec < HfPlusLeaf < 'a > > { let mut id = 0 ; let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | { add_profiling_node (node , context , counters , counter_queue , & mut id , seen_tees) } , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn profiler_wrapping_all_operators () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let runtime_context = flow . runtime_context () ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (& built . ir ()) ; let counters = RuntimeData :: new ("Fake") ; let counter_queue = RuntimeData :: new ("Fake") ; let pushed_down = built . with_default_optimize () . optimize_with (| ir | super :: profiling (ir , runtime_context , counters , counter_queue)) ; insta :: assert_debug_snapshot ! (& pushed_down . ir ()) ; let _ = pushed_down . compile_no_network :: < MultiGraph > () ; } } } pub mod properties { pub use std :: collections :: HashSet ; pub use stageleft :: * ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , SeenTees } ; pub use crate :: properties :: PropertyDatabase ; # [doc = " Allows us to convert the hydroflow datatype for folds to a binary operation for the algebra"] # [doc = " property tests."] # [allow (dead_code)] pub fn convert_hf_to_binary < I , A : Default , F : Fn (& mut A , I) > (f : F) -> impl Fn (I , I) -> A { move | a , b | { let mut acc = Default :: default () ; f (& mut acc , a) ; f (& mut acc , b) ; acc } } # [cfg (stageleft_macro)] impl PropertyDatabase { # [doc = " Tags the expression as commutative."] pub fn add_commutative_tag < 'a , I , A , F : Fn (& mut A , I) , Q : Quoted < 'a , F > + Clone > (& mut self , expr : Q ,) -> Q { let expr_clone = expr . clone () ; self . commutative . insert (expr_clone . splice ()) ; expr } pub fn is_tagged_commutative (& self , expr : & syn :: Expr) -> bool { self . commutative . contains (expr) } } pub fn properties_optimize_node < 'a > (node : & mut HfPlusNode < 'a > , db : & PropertyDatabase , seen_tees : & mut SeenTees < 'a > ,) { node . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , seen_tees ,) ; match node { HfPlusNode :: ReduceKeyed { f , .. } if db . is_tagged_commutative (& f . 0) => { dbg ! ("IDENTIFIED COMMUTATIVE OPTIMIZATION for {:?}" , & f) ; } _ => { } } } pub fn properties_optimize < 'a > (ir : Vec < HfPlusLeaf < 'a > > , db : & PropertyDatabase ,) -> Vec < HfPlusLeaf < 'a > > { let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use super :: * ; use crate :: deploy :: SingleProcessGraph ; use crate :: FlowBuilder ; # [test] fn test_property_database () { let mut db = PropertyDatabase :: default () ; assert ! (! db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; let _ = db . add_commutative_tag (q ! (| a : & mut i32 , b : i32 | * a += b)) ; assert ! (db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; } # [test] fn test_property_optimized () { let flow = FlowBuilder :: new () ; let mut database = PropertyDatabase :: default () ; let process = flow . process :: < () > () ; let counter_func = q ! (| count : & mut i32 , _ | * count += 1) ; let _ = database . add_commutative_tag (counter_func) ; flow . source_iter (& process , q ! (vec ! [])) . map (q ! (| string : String | (string , ()))) . tick_batch () . fold_keyed (q ! (|| 0) , counter_func) . all_ticks () . for_each (q ! (| (string , count) | println ! ("{}: {}" , string , count))) ; let built = flow . finalize () . optimize_with (| ir | properties_optimize (ir , & database)) . with_default_optimize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let _ = built . compile_no_network :: < SingleProcessGraph > () ; } } } pub use crate :: RuntimeContext ; # [cfg (stageleft_macro)] impl Copy for RuntimeContext < '_ > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Context > for RuntimeContext < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (quote ! (& context))) } } pub use crate :: HfCompiled ; # [cfg (stageleft_macro)] impl < 'a , ID > HfCompiled < 'a , ID > { pub fn hydroflow_ir (& self) -> & BTreeMap < usize , HydroflowGraph > { & self . hydroflow_ir } } # [cfg (stageleft_macro)] impl < 'a > HfCompiled < 'a , usize > { pub fn with_dynamic_id (self , id : impl Quoted < 'a , usize >) -> HfBuiltWithId < 'a > { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; let mut conditioned_tokens = None ; for (subgraph_id , flat_graph) in self . hydroflow_ir { let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; let my_extra_stmts = self . extra_stmts . get (& subgraph_id) . cloned () . unwrap_or_default () ; if let Some (conditioned_tokens) = conditioned_tokens . as_mut () { * conditioned_tokens = syn :: parse_quote ! { # conditioned_tokens else if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } } ; } else { conditioned_tokens = Some (syn :: parse_quote ! { if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } }) ; } } let conditioned_tokens : TokenStream = conditioned_tokens . unwrap () ; let id = id . splice () ; HfBuiltWithId { tokens : syn :: parse_quote ! ({ let __given_id = # id ; # conditioned_tokens else { panic ! ("Invalid node id: {}" , __given_id) ; } }) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfCompiled < 'a , () > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfCompiled < 'a , () > { fn to_tokens (mut self) -> (Option < TokenStream > , Option < TokenStream >) { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; if self . hydroflow_ir . len () != 1 { panic ! ("Expected exactly one subgraph in the Hydroflow IR") ; } let flat_graph = self . hydroflow_ir . remove (& 0) . unwrap () ; let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; (None , Some (tokens)) } } pub use crate :: HfBuiltWithId ; # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfBuiltWithId < 'a > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfBuiltWithId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (self . tokens)) } }
[INFO] [stdout] 1 + pub use std :: collections :: BTreeMap ; pub use std :: marker :: PhantomData ; pub use hydroflow :: scheduled :: context :: Context ; pub use hydroflow :: scheduled :: graph :: Hydroflow ; pub use hydroflow :: * ; pub use lang :: graph :: { partition_graph , HydroflowGraph } ; pub use proc_macro2 :: TokenStream ; pub use quote :: quote ; pub use stageleft :: runtime_support :: FreeVariable ; pub use stageleft :: Quoted ; pub mod runtime_support { pub use bincode ; } pub mod stream { pub use std :: cell :: RefCell ; pub use std :: hash :: Hash ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow :: bytes :: Bytes ; pub use hydroflow :: futures :: Sink ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: quote ; pub use serde :: de :: DeserializeOwned ; pub use serde :: Serialize ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use syn :: parse_quote ; pub use crate :: builder :: { ClusterIds , FlowLeaves } ; pub use crate :: cycle :: { CycleCollection , CycleComplete } ; pub use crate :: ir :: { DebugInstantiate , HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { CanSend , Location , LocationId } ; pub use crate :: { Cluster , Optional , Singleton } ; pub use crate :: stream :: Unbounded ; pub use crate :: stream :: Bounded ; pub use crate :: stream :: NoTick ; pub use crate :: stream :: Tick ; pub use crate :: stream :: Stream ; # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Stream { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Stream < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Stream { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , C , N > > ,) -> Stream < 'a , (T , O) , W , C , N > where O : Clone , { let other : Optional < 'a , O , Bounded , C , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn cross_product < O > (self , other : Stream < 'a , O , W , C , N >) -> Stream < 'a , (T , O) , W , C , N > where T : Clone , O : Clone , { if self . location_kind != other . location_kind { panic ! ("cross_product must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossProduct (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn union (self , other : Stream < 'a , T , W , C , N >) -> Stream < 'a , T , W , C , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn dest_sink < S : Unpin + Sink < T > + 'a > (self , sink : impl Quoted < 'a , S >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: DestSink { sink : sink . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn first (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } # [doc = " Allow this stream through if the other stream has elements, otherwise the output is empty."] pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } # [doc = " Allow this stream through if the other stream is empty, otherwise the output is empty."] pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn enumerate (self) -> Stream < 'a , (usize , T) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Enumerate (Box :: new (self . ir_node . into_inner ())) ,) } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn sort (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Ord , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Sort (Box :: new (self . ir_node . into_inner ())) ,) } pub fn count (self) -> Singleton < 'a , usize , Bounded , Tick , N > { self . fold (q ! (|| 0usize) , q ! (| count , _ | * count += 1)) } pub fn delta (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } pub fn unique (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Eq + Hash , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unique (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn tick_batch (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_prefix (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { self . tick_batch () . persist () } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn for_each < F : Fn (T) + 'a > (self , f : impl IntoQuotedMut < 'a , F >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: ForEach { input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , f : f . splice () . into () , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Unbounded , NoTick , N > { pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . tick_batch () . continue_if (samples . first ()) . all_ticks () } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Unbounded , NoTick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , C , N : Location > Stream < 'a , T , Bounded , C , N > { pub fn filter_not_in (self , other : Stream < 'a , T , Bounded , C , N >) -> Stream < 'a , T , Bounded , C , N > where T : Eq + Hash , { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Difference (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Stream < 'a , & T , W , C , N > { pub fn cloned (self) -> Stream < 'a , T , W , C , N > { self . map (q ! (| d | d . clone ())) } } # [cfg (stageleft_macro)] impl < 'a , K , V1 , W , C , N : Location > Stream < 'a , (K , V1) , W , C , N > { pub fn join < W2 , V2 > (self , n : Stream < 'a , (K , V2) , W2 , C , N > ,) -> Stream < 'a , (K , (V1 , V2)) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Join (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } pub fn anti_join < W2 > (self , n : Stream < 'a , K , W2 , C , N >) -> Stream < 'a , (K , V1) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("anti_join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: AntiJoin (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , K : Eq + Hash , V , N : Location > Stream < 'a , (K , V) , Bounded , Tick , N > { pub fn fold_keyed < A , I : Fn () -> A + 'a , F : Fn (& mut A , V) + 'a > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , A) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FoldKeyed { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce_keyed < F : Fn (& mut V , V) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , V) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: ReduceKeyed { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } pub fn get_this_crate () -> TokenStream { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , Span :: call_site ()) ; quote ! { # ident } } } } pub fn serialize_bincode < T : Serialize > (is_demux : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if is_demux { parse_quote ! { map (| (id , data) | { (id , # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into ()) }) } } else { parse_quote ! { map (| data | { # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into () }) } } } pub fn deserialize_bincode < T : DeserializeOwned > (tagged : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if tagged { parse_quote ! { map (| res | { let (id , b) = res . unwrap () ; (id , # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& b) . unwrap ()) }) } } else { parse_quote ! { map (| res | { # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& res . unwrap ()) . unwrap () }) } } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn send_bincode < N2 : Location , CoreType > (self , other : & N2 ,) -> Stream < 'a , N :: Out < CoreType > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T > , CoreType : Serialize + DeserializeOwned , { let serialize_pipeline = Some (serialize_bincode :: < CoreType > (N :: is_demux ())) ; let deserialize_pipeline = Some (deserialize_bincode :: < CoreType > (N :: is_tagged ())) ; Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bytes < N2 : Location > (self , other : & N2 ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T > , { Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline : None , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline : if N :: is_tagged () { Some (parse_quote ! (map (| (id , b) | (id , b . unwrap () . freeze ())))) } else { Some (parse_quote ! (map (| b | b . unwrap () . freeze ()))) } , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bincode_interleaved < N2 : Location , Tag , CoreType > (self , other : & N2 ,) -> Stream < 'a , CoreType , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T , Out < CoreType > = (Tag , CoreType) > , CoreType : Serialize + DeserializeOwned , { self . send_bincode :: < N2 , CoreType > (other) . map (q ! (| (_ , b) | b)) } pub fn send_bytes_interleaved < N2 : Location , Tag > (self , other : & N2 ,) -> Stream < 'a , Bytes , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T , Out < Bytes > = (Tag , Bytes) > , { self . send_bytes :: < N2 > (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bincode < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < T > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) > , T : Clone + Serialize + DeserializeOwned , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bincode (other) } pub fn broadcast_bincode_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , T , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) , Out < T > = (Tag , T) > + 'a , T : Clone + Serialize + DeserializeOwned , { self . broadcast_bincode (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bytes < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) > + 'a , T : Clone , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bytes (other) } pub fn broadcast_bytes_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , Bytes , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) , Out < Bytes > = (Tag , Bytes) > + 'a , T : Clone , { self . broadcast_bytes (other) . map (q ! (| (_ , b) | b)) } } } pub use stream :: { Bounded , NoTick , Stream , Tick , Unbounded } ; pub mod singleton { pub use std :: cell :: RefCell ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use crate :: builder :: FlowLeaves ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial , CycleComplete } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: Stream ; pub use crate :: singleton :: CrossResult ; # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Singleton < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Singleton :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } pub use crate :: singleton :: Singleton ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Singleton { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleComplete < 'a > for Singleton < 'a , T , Bounded , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleCollectionWithInitial < 'a > for Singleton < 'a , T , Bounded , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , initial : Self , l : LocationId ,) -> Self { Singleton :: new (l , ir_leaves , HfPlusNode :: Union (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , }) , initial . ir_node . into_inner () . into () ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Singleton < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Singleton { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , U , W , C , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (Self :: other_ir_node (other)) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Singleton < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CrossSingleton (Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , Box :: new (HfPlusNode :: Unpersist (Box :: new (Self :: other_ir_node (other)))) ,))) ,) } } pub use crate :: singleton :: Optional ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Optional { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } pub fn some (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: new (singleton . location_kind , singleton . ir_leaves , singleton . ir_node . into_inner () ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > From < Singleton < 'a , T , W , C , N > > for Optional < 'a , T , W , C , N > { fn from (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: some (singleton) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Optional < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Optional { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn into_stream (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , Tick , N > > ,) -> Optional < 'a , (T , O) , Bounded , Tick , N > where O : Clone , { let other : Optional < 'a , O , Bounded , Tick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn union (self , other : Optional < 'a , T , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Optional < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_samples (self) -> Stream < 'a , T , Unbounded , NoTick , N > { self . latest_tick () . all_ticks () } pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . latest_tick () . continue_if (samples . first ()) . latest () . tick_samples () } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Unbounded , NoTick , N > > ,) -> Optional < 'a , (T , O) , Unbounded , NoTick , N > where O : Clone , { let other : Optional < 'a , O , Unbounded , NoTick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } self . latest_tick () . cross_singleton (other . latest_tick ()) . latest () } } } pub use singleton :: { Optional , Singleton } ; pub mod location { pub use std :: marker :: PhantomData ; pub use crate :: location :: LocationId ; pub use crate :: location :: Location ; pub use crate :: location :: Process ; # [cfg (stageleft_macro)] impl < P > Clone for Process < P > { fn clone (& self) -> Self { Process { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < P > Location for Process < P > { fn id (& self) -> LocationId { LocationId :: Process (self . id) } } pub use crate :: location :: Cluster ; # [cfg (stageleft_macro)] impl < C > Clone for Cluster < C > { fn clone (& self) -> Self { Cluster { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < C > Location for Cluster < C > { fn id (& self) -> LocationId { LocationId :: Cluster (self . id) } } pub use crate :: location :: CanSend ; # [cfg (stageleft_macro)] impl < P1 , P2 > CanSend < Process < P2 > > for Process < P1 > { type In < T > = T ; type Out < T > = T ; fn is_demux () -> bool { false } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < P1 , C2 > CanSend < Cluster < C2 > > for Process < P1 > { type In < T > = (u32 , T) ; type Out < T > = T ; fn is_demux () -> bool { true } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < C1 , P2 > CanSend < Process < P2 > > for Cluster < C1 > { type In < T > = T ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { false } fn is_tagged () -> bool { true } } # [cfg (stageleft_macro)] impl < C1 , C2 > CanSend < Cluster < C2 > > for Cluster < C1 > { type In < T > = (u32 , T) ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { true } fn is_tagged () -> bool { true } } } pub use location :: { Cluster , Process } ; pub mod deploy { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use stageleft :: Quoted ; pub mod graphs { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use super :: { LocalDeploy , Node , ProcessSpec } ; pub use crate :: deploy :: graphs :: SingleProcessGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for SingleProcessGraph { type Process = SingleNode ; type Cluster = SingleNode ; type Meta = () ; type GraphId = () ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { SingleNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { SingleNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , SingleProcessGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> SingleNode { SingleNode { } } } pub use crate :: deploy :: graphs :: SingleNode ; # [cfg (stageleft_macro)] impl Node for SingleNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } pub use crate :: deploy :: graphs :: MultiGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for MultiGraph { type Process = MultiNode ; type Cluster = MultiNode ; type Meta = () ; type GraphId = usize ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { MultiNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { MultiNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , MultiGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> MultiNode { MultiNode { } } } pub use crate :: deploy :: graphs :: MultiNode ; # [cfg (stageleft_macro)] impl Node for MultiNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } } pub use graphs :: * ; pub use crate :: deploy :: LocalDeploy ; pub use crate :: deploy :: Deploy ; # [cfg (stageleft_macro)] impl < 'a , T : Deploy < 'a , Process = N , Cluster = C , Meta = M , GraphId = R > , N : Node < Meta = M > , C : Node < Meta = M > , M : Default , R , > LocalDeploy < 'a > for T { type Process = N ; type Cluster = C ; type Meta = M ; type GraphId = R ; fn has_trivial_node () -> bool { < T as Deploy < 'a > > :: has_trivial_node () } fn trivial_process (id : usize) -> Self :: Process { < T as Deploy < 'a > > :: trivial_process (id) } fn trivial_cluster (id : usize) -> Self :: Cluster { < T as Deploy < 'a > > :: trivail_cluster (id) } } pub use crate :: deploy :: ProcessSpec ; pub use crate :: deploy :: ClusterSpec ; pub use crate :: deploy :: Node ; } pub use deploy :: { ClusterSpec , Deploy , ProcessSpec } ; pub mod cycle { pub use std :: marker :: PhantomData ; pub use crate :: builder :: FlowLeaves ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: cycle :: CycleComplete ; pub use crate :: cycle :: CycleCollection ; pub use crate :: cycle :: CycleCollectionWithInitial ; pub use crate :: cycle :: HfCycle ; # [cfg (stageleft_macro)] impl < 'a , S : CycleComplete < 'a > > HfCycle < 'a , S > { pub fn complete (self , stream : S) { let ident = self . ident ; S :: complete (stream , ident) } } } pub use cycle :: HfCycle ; pub mod builder { pub use std :: cell :: RefCell ; pub use std :: collections :: HashMap ; pub use std :: marker :: PhantomData ; pub use std :: rc :: Rc ; pub use std :: time :: Duration ; pub use hydroflow :: futures :: stream :: Stream as FuturesStream ; pub use hydroflow :: { tokio , tokio_stream } ; pub use internal :: TokenStream ; pub use proc_macro2 :: Span ; pub use quote :: quote ; pub use runtime_support :: FreeVariable ; pub use stageleft :: * ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Cluster , Location , LocationId , Process } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: { HfCycle , Optional , RuntimeContext , Singleton , Stream } ; pub mod built { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use hydroflow_lang :: graph :: { eliminate_extra_unions_tees , HydroflowGraph } ; pub use super :: deploy :: { DeployFlow , DeployResult } ; pub use crate :: deploy :: { ClusterSpec , Deploy , LocalDeploy , ProcessSpec } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Cluster , Process } ; pub use crate :: HfCompiled ; pub use crate :: builder :: built :: BuiltFlow ; # [cfg (stageleft_macro)] impl < 'a > Drop for BuiltFlow < 'a > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped BuiltFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn ir (& self) -> & Vec < HfPlusLeaf < 'a > > { & self . ir } pub fn optimize_with (mut self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> BuiltFlow < 'a > { self . used = true ; BuiltFlow { ir : f (std :: mem :: take (& mut self . ir)) , processes : std :: mem :: take (& mut self . processes) , clusters : std :: mem :: take (& mut self . clusters) , used : false , _phantom : PhantomData , } } } pub fn build_inner (ir : & mut Vec < HfPlusLeaf >) -> BTreeMap < usize , HydroflowGraph > { let mut builders = BTreeMap :: new () ; let mut built_tees = HashMap :: new () ; let mut next_stmt_id = 0 ; for leaf in ir { leaf . emit (& mut builders , & mut built_tees , & mut next_stmt_id) ; } builders . into_iter () . map (| (k , v) | { let (mut flat_graph , _ , _) = v . build () ; eliminate_extra_unions_tees (& mut flat_graph) ; (k , flat_graph) }) . collect () } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn compile_no_network < D : LocalDeploy < 'a > > (mut self) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; HfCompiled { hydroflow_ir : build_inner (& mut self . ir) , extra_stmts : BTreeMap :: new () , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> BuiltFlow < 'a > { self . optimize_with (crate :: persist_pullup :: persist_pullup) } fn into_deploy < D : LocalDeploy < 'a > > (mut self) -> DeployFlow < 'a , D > { self . used = true ; let processes = if D :: has_trivial_node () { self . processes . iter () . map (| id | (* id , D :: trivial_process (* id))) . collect () } else { HashMap :: new () } ; let clusters = if D :: has_trivial_node () { self . clusters . iter () . map (| id | (* id , D :: trivial_cluster (* id))) . collect () } else { HashMap :: new () } ; DeployFlow { ir : std :: mem :: take (& mut self . ir) , nodes : processes , clusters , used : false , _phantom : PhantomData , } } pub fn with_process < P , D : LocalDeploy < 'a > > (self , process : & Process < P > , spec : impl ProcessSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_process (process , spec) } pub fn with_cluster < C , D : LocalDeploy < 'a > > (self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_cluster (cluster , spec) } pub fn compile < D : Deploy < 'a > + 'a > (self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . into_deploy :: < D > () . compile (env) } pub fn deploy < D : Deploy < 'a , CompileEnv = () > + 'a > (self , env : & mut D :: InstantiateEnv ,) -> DeployResult < 'a , D > { self . into_deploy :: < D > () . deploy (env) } } } pub mod deploy { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use proc_macro2 :: Span ; pub use stageleft :: Quoted ; pub use super :: built :: build_inner ; pub use crate :: deploy :: { LocalDeploy , Node } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: { Cluster , ClusterSpec , Deploy , HfCompiled , Process , ProcessSpec } ; pub use crate :: builder :: deploy :: DeployFlow ; # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > Drop for DeployFlow < 'a , D > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped DeployFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > DeployFlow < 'a , D > { pub fn with_process < P > (mut self , process : & Process < P > , spec : impl ProcessSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < P > () . to_string () ; self . nodes . insert (process . id , spec . build (process . id , & tag_name)) ; self } pub fn with_cluster < C > (mut self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < C > () . to_string () ; self . clusters . insert (cluster . id , spec . build (cluster . id , & tag_name)) ; self } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployFlow < 'a , D > { pub fn compile (mut self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; let mut seen_tees : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | leaf . compile_network :: < D > (env , & mut seen_tees , & self . nodes , & self . clusters)) . collect () ; let extra_stmts = self . extra_stmts (env) ; HfCompiled { hydroflow_ir : build_inner (& mut ir_leaves_networked) , extra_stmts , _phantom : PhantomData , } } fn extra_stmts (& self , env : & < D as Deploy < 'a > > :: CompileEnv) -> BTreeMap < usize , Vec < syn :: Stmt > > { let all_locations_count = self . nodes . len () + self . clusters . len () ; let mut extra_stmts : BTreeMap < usize , Vec < syn :: Stmt > > = BTreeMap :: new () ; for & c_id in self . clusters . keys () { let self_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , c_id) , Span :: call_site () ,) ; let self_id_expr = D :: cluster_self_id (env) . splice () ; extra_stmts . entry (c_id) . or_default () . push (syn :: parse_quote ! { let # self_id_ident = # self_id_expr ; }) ; for other_location in 0 .. all_locations_count { let other_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , c_id) , Span :: call_site () ,) ; let other_id_expr = D :: cluster_ids (env , c_id) . splice () ; extra_stmts . entry (other_location) . or_default () . push (syn :: parse_quote ! { let # other_id_ident = # other_id_expr ; }) ; } } extra_stmts } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a , CompileEnv = () > > DeployFlow < 'a , D > { # [must_use] pub fn deploy (mut self , env : & mut D :: InstantiateEnv) -> DeployResult < 'a , D > { self . used = true ; let mut seen_tees_instantiate : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | { leaf . compile_network :: < D > (& () , & mut seen_tees_instantiate , & self . nodes , & self . clusters ,) }) . collect () ; let mut compiled = build_inner (& mut ir_leaves_networked) ; let mut extra_stmts = self . extra_stmts (& ()) ; let mut meta = D :: Meta :: default () ; let (mut processes , mut clusters) = (std :: mem :: take (& mut self . nodes) . into_iter () . map (| (node_id , node) | { node . instantiate (env , & mut meta , compiled . remove (& node_id) . unwrap () , extra_stmts . remove (& node_id) . unwrap_or_default () ,) ; (node_id , node) }) . collect :: < HashMap < _ , _ > > () , std :: mem :: take (& mut self . clusters) . into_iter () . map (| (cluster_id , cluster) | { cluster . instantiate (env , & mut meta , compiled . remove (& cluster_id) . unwrap () , extra_stmts . remove (& cluster_id) . unwrap_or_default () ,) ; (cluster_id , cluster) }) . collect :: < HashMap < _ , _ > > () ,) ; for node in processes . values_mut () { node . update_meta (& meta) ; } for cluster in clusters . values_mut () { cluster . update_meta (& meta) ; } let mut seen_tees_connect = HashMap :: new () ; for leaf in ir_leaves_networked { leaf . connect_network (& mut seen_tees_connect) ; } DeployResult { processes , clusters , } } } pub use crate :: builder :: deploy :: DeployResult ; # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployResult < 'a , D > { pub fn get_process < P > (& self , p : & Process < P >) -> & D :: Process { let id = match p . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . processes . get (& id) . unwrap () } pub fn get_cluster < C > (& self , c : & Cluster < C >) -> & D :: Cluster { let id = match c . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . clusters . get (& id) . unwrap () } } } # [doc = " Tracks the leaves of the dataflow IR. This is referenced by"] # [doc = " `Stream` and `HfCycle` to build the IR. The inner option will"] # [doc = " be set to `None` when this builder is finalized."] pub type FlowLeaves < 'a > = Rc < RefCell < Option < Vec < HfPlusLeaf < 'a > > > > > ; pub use crate :: builder :: ClusterIds ; # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Vec < u32 > > for ClusterIds < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , & 'a Vec < u32 > > for ClusterIds < 'a > { } # [derive (Copy , Clone)] pub struct ClusterSelfId < 'a > { pub id : usize , pub _phantom : PhantomData < & 'a mut & 'a u32 > , } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < u32 > for ClusterSelfId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , u32 > for ClusterSelfId < 'a > { } pub use crate :: builder :: FlowBuilder ; # [cfg (stageleft_macro)] impl < 'a > Drop for FlowBuilder < 'a > { fn drop (& mut self) { if ! self . finalized { panic ! ("Dropped FlowBuilder without finalizing, you may have forgotten to call `with_default_optimize`, `optimize_with`, or `finalize`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > QuotedContext for FlowBuilder < 'a > { fn create () -> Self { FlowBuilder :: new () } } # [cfg (stageleft_macro)] impl < 'a > FlowBuilder < 'a > { # [allow (clippy :: new_without_default)] pub fn new () -> FlowBuilder < 'a > { FlowBuilder { ir_leaves : Rc :: new (RefCell :: new (Some (Vec :: new ()))) , nodes : RefCell :: new (vec ! []) , clusters : RefCell :: new (vec ! []) , cycle_ids : RefCell :: new (HashMap :: new ()) , next_node_id : RefCell :: new (0) , finalized : false , _phantom : PhantomData , } } pub fn finalize (mut self) -> built :: BuiltFlow < 'a > { self . finalized = true ; built :: BuiltFlow { ir : self . ir_leaves . borrow_mut () . take () . unwrap () , processes : self . nodes . replace (vec ! []) , clusters : self . clusters . replace (vec ! []) , used : false , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> built :: BuiltFlow < 'a > { self . finalize () . with_default_optimize () } pub fn optimize_with (self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> built :: BuiltFlow < 'a > { self . finalize () . optimize_with (f) } pub fn ir_leaves (& self) -> & FlowLeaves < 'a > { & self . ir_leaves } pub fn process < P > (& self) -> Process < P > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . nodes . borrow_mut () . push (id) ; Process { id , _phantom : PhantomData , } } pub fn cluster < C > (& self) -> Cluster < C > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . clusters . borrow_mut () . push (id) ; Cluster { id , _phantom : PhantomData , } } pub fn runtime_context (& self) -> RuntimeContext < 'a > { RuntimeContext { _phantom : PhantomData , } } pub fn cluster_members < C > (& self , cluster : & Cluster < C > ,) -> impl Quoted < 'a , & 'a Vec < u32 > > + Copy + 'a { ClusterIds { id : cluster . id , _phantom : PhantomData , } } pub fn cluster_self_id < C > (& self , cluster : & Cluster < C >) -> impl Quoted < 'a , u32 > + Copy + 'a { ClusterSelfId { id : cluster . id , _phantom : PhantomData , } } pub fn spin < L : Location > (& self , on : & L) -> Stream < 'a , () , Unbounded , NoTick , L > { Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Spin () , location_kind : on . id () , })) ,) } pub fn spin_batch < L : Location > (& self , on : & L , batch_size : impl Quoted < 'a , usize > + Copy + 'a ,) -> Stream < 'a , () , Bounded , Tick , L > { self . spin (on) . flat_map (q ! (move | _ | 0 .. batch_size)) . map (q ! (| _ | ())) . tick_batch () } pub fn source_stream < T , E : FuturesStream < Item = T > + Unpin , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Unbounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Stream (e . into ()) , location_kind : on . id () , })) ,) } pub fn source_iter < T , E : IntoIterator < Item = T > , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Bounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , })) ,) } pub fn singleton < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Singleton < 'a , T , Bounded , NoTick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Singleton :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,)))) ,) } pub fn singleton_first_tick < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Optional < 'a , T , Bounded , Tick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,) } pub fn source_interval < L : Location > (& self , on : & L , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , () , Unbounded , NoTick , L > { let interval = interval . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : on . id () , })) ,) } pub fn source_interval_delayed < L : Location > (& self , on : & L , delay : impl Quoted < 'a , Duration > + Copy + 'a , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , tokio :: time :: Instant , Unbounded , NoTick , L > { self . source_stream (on , q ! (tokio_stream :: wrappers :: IntervalStream :: new (tokio :: time :: interval_at (tokio :: time :: Instant :: now () + delay , interval))) ,) . tick_batch () . first () . latest () } pub fn cycle < S : CycleCollection < 'a > > (& self , on : & S :: Location) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , on . id ()) ,) } pub fn cycle_with_initial < S : CycleCollectionWithInitial < 'a > > (& self , on : & S :: Location , initial : S ,) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , initial , on . id ()) ,) } } } pub use builder :: FlowBuilder ; pub mod ir { pub use core :: panic ; pub use std :: cell :: RefCell ; pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow_lang :: graph :: FlatGraphBuilder ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: ToTokens ; pub use syn :: parse_quote ; pub use crate :: deploy :: Deploy ; pub use crate :: location :: LocationId ; pub use crate :: ir :: DebugExpr ; # [cfg (stageleft_macro)] impl From < syn :: Expr > for DebugExpr { fn from (expr : syn :: Expr) -> DebugExpr { DebugExpr (expr) } } # [cfg (stageleft_macro)] impl Deref for DebugExpr { type Target = syn :: Expr ; fn deref (& self) -> & Self :: Target { & self . 0 } } # [cfg (stageleft_macro)] impl ToTokens for DebugExpr { fn to_tokens (& self , tokens : & mut TokenStream) { self . 0 . to_tokens (tokens) ; } } # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugExpr { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "{}" , self . 0 . to_token_stream ()) } } pub use crate :: ir :: DebugInstantiate ; # [cfg (stageleft_macro)] impl < 'a > std :: fmt :: Debug for DebugInstantiate < 'a > { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<network instantiate>") } } pub use crate :: ir :: DebugPipelineFn ; # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugPipelineFn { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<function>") } } pub use crate :: ir :: HfPlusSource ; pub use crate :: ir :: HfPlusLeaf ; # [cfg (stageleft_macro)] impl < 'a > HfPlusLeaf < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . compile_network :: < D > (compile_env , s , nodes , clusters) ; } , seen_tees ,) } pub fn connect_network (self , seen_tees : & mut SeenTees < 'a >) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . connect_network (s) ; } , seen_tees ,) } pub fn transform_children (self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) -> HfPlusLeaf < 'a > { match self { HfPlusLeaf :: ForEach { f , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: ForEach { f , input } } HfPlusLeaf :: DestSink { sink , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: DestSink { sink , input } } HfPlusLeaf :: CycleSink { ident , location_kind , mut input , } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: CycleSink { ident , location_kind , input , } } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) { match self { HfPlusLeaf :: ForEach { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> for_each (# f) ; }) ; } HfPlusLeaf :: DestSink { sink , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink) ; }) ; } HfPlusLeaf :: CycleSink { ident , location_kind , input , } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; assert_eq ! (input_location_id , * location_id , "cycle_sink location mismatch") ; graph_builders . entry (* location_id) . or_default () . add_statement (parse_quote ! { # ident = # input_ident ; }) ; } } } } pub use crate :: ir :: HfPlusNode ; pub type SeenTees < 'a > = HashMap < * const RefCell < HfPlusNode < 'a > > , Rc < RefCell < HfPlusNode < 'a > > > > ; # [cfg (stageleft_macro)] impl < 'a > HfPlusNode < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (& mut self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) { self . transform_children (| n , s | n . compile_network :: < D > (compile_env , s , nodes , clusters) , seen_tees ,) ; if let HfPlusNode :: Network { from_location , to_location , instantiate_fn , .. } = self { let (sink_expr , source_expr , connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { let ((sink , source) , connect_fn) = match (from_location , to_location) { (LocationId :: Process (from) , LocationId :: Process (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: o2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Process (from) , LocationId :: Cluster (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: o2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Process (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: m2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Cluster (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: m2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } } ; (sink , source , connect_fn) } DebugInstantiate :: Finalized (_ , _ , _) => panic ! ("network already finalized") , } ; * instantiate_fn = DebugInstantiate :: Finalized (sink_expr , source_expr , connect_fn) ; } } pub fn connect_network (& mut self , seen_tees : & mut SeenTees < 'a >) { self . transform_children (| n , s | n . connect_network (s) , seen_tees) ; if let HfPlusNode :: Network { instantiate_fn , .. } = self { match instantiate_fn { DebugInstantiate :: Building () => panic ! ("network not built") , DebugInstantiate :: Finalized (_ , _ , ref connect_fn) => { connect_fn () ; } } } } pub fn transform_children (& mut self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) { match self { HfPlusNode :: Placeholder => { panic ! () ; } HfPlusNode :: Source { .. } => { } HfPlusNode :: CycleSource { .. } => { } HfPlusNode :: Tee { inner } => { if let Some (transformed) = seen_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { * inner = transformed . clone () ; } else { let transformed_cell = Rc :: new (RefCell :: new (HfPlusNode :: Placeholder)) ; seen_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , transformed_cell . clone () ,) ; let mut orig = inner . replace (HfPlusNode :: Placeholder) ; transform (& mut orig , seen_tees) ; * transformed_cell . borrow_mut () = orig ; * inner = transformed_cell ; } } HfPlusNode :: Persist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Unpersist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Delta (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Union (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossProduct (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossSingleton (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Join (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Difference (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: AntiJoin (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Map { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FlatMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Filter { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FilterMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Sort (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: DeferTick (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Enumerate (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Inspect { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Unique (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Fold { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FoldKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Reduce { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: ReduceKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Network { input , .. } => { transform (input . as_mut () , seen_tees) ; } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) -> (syn :: Ident , usize) { match self { HfPlusNode :: Placeholder => { panic ! () } HfPlusNode :: Persist (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let persist_id = * next_stmt_id ; * next_stmt_id += 1 ; let persist_ident = syn :: Ident :: new (& format ! ("stream_{}" , persist_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # persist_ident = # inner_ident -> persist ::<'static > () ; }) ; (persist_ident , location) } HfPlusNode :: Unpersist (_) => { panic ! ("Unpersist is a marker node and should have been optimized away. This is likely a compiler bug.") } HfPlusNode :: Delta (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let delta_id = * next_stmt_id ; * next_stmt_id += 1 ; let delta_ident = syn :: Ident :: new (& format ! ("stream_{}" , delta_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # delta_ident = # inner_ident -> multiset_delta () ; }) ; (delta_ident , location) } HfPlusNode :: Source { source , location_kind , } => { let source_id = * next_stmt_id ; * next_stmt_id += 1 ; let source_ident = syn :: Ident :: new (& format ! ("stream_{}" , source_id) , Span :: call_site ()) ; let source_stmt = match source { HfPlusSource :: Stream (expr) => { parse_quote ! { # source_ident = source_stream (# expr) ; } } HfPlusSource :: Iter (expr) => { parse_quote ! { # source_ident = source_iter (# expr) ; } } HfPlusSource :: Interval (expr) => { parse_quote ! { # source_ident = source_interval (# expr) ; } } HfPlusSource :: Spin () => { parse_quote ! { # source_ident = spin () ; } } } ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; graph_builders . entry (* location_id) . or_default () . add_statement (source_stmt) ; (source_ident , * location_id) } HfPlusNode :: CycleSource { ident , location_kind , } => { let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; (ident . clone () , * location_id) } HfPlusNode :: Tee { inner } => { if let Some (ret) = built_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { ret . clone () } else { let (inner_ident , inner_location_id) = inner . borrow () . emit (graph_builders , built_tees , next_stmt_id) ; let tee_id = * next_stmt_id ; * next_stmt_id += 1 ; let tee_ident = syn :: Ident :: new (& format ! ("stream_{}" , tee_id) , Span :: call_site ()) ; let builder = graph_builders . entry (inner_location_id) . or_default () ; builder . add_statement (parse_quote ! { # tee_ident = # inner_ident -> tee () ; }) ; built_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , (tee_ident . clone () , inner_location_id) ,) ; (tee_ident , inner_location_id) } } HfPlusNode :: Union (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "union inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let union_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # union_ident = union () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [0] # union_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # union_ident ; }) ; (union_ident , left_location_id) } HfPlusNode :: CrossSingleton (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "cross_singleton inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let cross_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # cross_ident = cross_singleton () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [input] # cross_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [single] # cross_ident ; }) ; (cross_ident , left_location_id) } HfPlusNode :: CrossProduct (..) | HfPlusNode :: Join (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: CrossProduct (..)) { parse_quote ! (cross_join_multiset) } else { parse_quote ! (join_multiset) } ; let (HfPlusNode :: CrossProduct (left , right) | HfPlusNode :: Join (left , right)) = self else { unreachable ! () } ; let (left_inner , left_was_persist) = if let HfPlusNode :: Persist (left) = left . as_ref () { (left , true) } else { (left , false) } ; let (right_inner , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left_inner . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right_inner . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "join / cross product inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; match (left_was_persist , right_was_persist) { (true , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'static > () ; }) ; } (true , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'tick > () ; }) ; } (false , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } (false , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } } ; builder . add_statement (parse_quote ! { # left_ident -> [0] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Difference (..) | HfPlusNode :: AntiJoin (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Difference (..)) { parse_quote ! (difference_multiset) } else { parse_quote ! (anti_join_multiset) } ; let (HfPlusNode :: Difference (left , right) | HfPlusNode :: AntiJoin (left , right)) = self else { unreachable ! () } ; let (right , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "difference / anti join inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; if right_was_persist { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } else { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } builder . add_statement (parse_quote ! { # left_ident -> [pos] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [neg] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Map { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let map_id = * next_stmt_id ; * next_stmt_id += 1 ; let map_ident = syn :: Ident :: new (& format ! ("stream_{}" , map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # map_ident = # input_ident -> map (# f) ; }) ; (map_ident , input_location_id) } HfPlusNode :: FlatMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let flat_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let flat_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , flat_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # flat_map_ident = # input_ident -> flat_map (# f) ; }) ; (flat_map_ident , input_location_id) } HfPlusNode :: Filter { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_ident = # input_ident -> filter (# f) ; }) ; (filter_ident , input_location_id) } HfPlusNode :: FilterMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_map_ident = # input_ident -> filter_map (# f) ; }) ; (filter_map_ident , input_location_id) } HfPlusNode :: Sort (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sort_id = * next_stmt_id ; * next_stmt_id += 1 ; let sort_ident = syn :: Ident :: new (& format ! ("stream_{}" , sort_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # sort_ident = # input_ident -> sort () ; }) ; (sort_ident , input_location_id) } HfPlusNode :: DeferTick (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let defer_tick_id = * next_stmt_id ; * next_stmt_id += 1 ; let defer_tick_ident = syn :: Ident :: new (& format ! ("stream_{}" , defer_tick_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # defer_tick_ident = # input_ident -> defer_tick_lazy () ; }) ; (defer_tick_ident , input_location_id) } HfPlusNode :: Enumerate (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let enumerate_id = * next_stmt_id ; * next_stmt_id += 1 ; let enumerate_ident = syn :: Ident :: new (& format ! ("stream_{}" , enumerate_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # enumerate_ident = # input_ident -> enumerate () ; }) ; (enumerate_ident , input_location_id) } HfPlusNode :: Inspect { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let inspect_id = * next_stmt_id ; * next_stmt_id += 1 ; let inspect_ident = syn :: Ident :: new (& format ! ("stream_{}" , inspect_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # inspect_ident = # input_ident -> inspect (# f) ; }) ; (inspect_ident , input_location_id) } HfPlusNode :: Unique (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let unique_id = * next_stmt_id ; * next_stmt_id += 1 ; let unique_ident = syn :: Ident :: new (& format ! ("stream_{}" , unique_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # unique_ident = # input_ident -> unique ::<'tick > () ; }) ; (unique_ident , input_location_id) } HfPlusNode :: Fold { .. } | HfPlusNode :: FoldKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Fold { .. }) { parse_quote ! (fold) } else { parse_quote ! (fold_keyed) } ; let (HfPlusNode :: Fold { init , acc , input } | HfPlusNode :: FoldKeyed { init , acc , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let fold_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'static > (# init , # acc) ; }) ; } else { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'tick > (# init , # acc) ; }) ; } (fold_ident , input_location_id) } HfPlusNode :: Reduce { .. } | HfPlusNode :: ReduceKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Reduce { .. }) { parse_quote ! (reduce) } else { parse_quote ! (reduce_keyed) } ; let (HfPlusNode :: Reduce { f , input } | HfPlusNode :: ReduceKeyed { f , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let reduce_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'static > (# f) ; }) ; } else { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'tick > (# f) ; }) ; } (reduce_ident , input_location_id) } HfPlusNode :: Network { from_location : _ , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input , } => { let (sink_expr , source_expr , _connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { panic ! ("Expected the network to be finalized") } DebugInstantiate :: Finalized (sink , source , connect_fn) => { (sink , source , connect_fn) } } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sender_builder = graph_builders . entry (input_location_id) . or_default () ; if let Some (serialize_pipeline) = serialize_pipeline { sender_builder . add_statement (parse_quote ! { # input_ident -> # serialize_pipeline -> dest_sink (# sink_expr) ; }) ; } else { sender_builder . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink_expr) ; }) ; } let to_id = match to_location { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let receiver_builder = graph_builders . entry (* to_id) . or_default () ; let receiver_stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let receiver_stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , receiver_stream_id) , Span :: call_site ()) ; if let Some (deserialize_pipeline) = deserialize_pipeline { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) -> # deserialize_pipeline ; }) ; } else { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) ; }) ; } (receiver_stream_ident , * to_id) } } } } } pub mod persist_pullup { pub use std :: cell :: RefCell ; pub use std :: collections :: HashSet ; pub use std :: ops :: Deref ; pub use crate :: ir :: * ; pub fn persist_pullup_node < 'a > (node : & mut HfPlusNode < 'a > , seen_tees : & mut SeenTees < 'a > , persist_pulled_tees : & mut HashSet < * const RefCell < HfPlusNode < 'a > > > ,) { node . transform_children (| n , s | persist_pullup_node (n , s , persist_pulled_tees) , seen_tees ,) ; match node { HfPlusNode :: Unpersist (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Unpersist (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Delta (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Delta (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Tee { inner } => { if persist_pulled_tees . contains (& (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >)) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } else { let inner_borrow = inner . borrow () ; if let HfPlusNode :: Persist (_) = inner_borrow . deref () { drop (inner_borrow) ; persist_pulled_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >) ; if let HfPlusNode :: Persist (box behind_persist) = inner . replace (HfPlusNode :: Placeholder) { * inner . borrow_mut () = behind_persist ; } else { unreachable ! () } * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } } } HfPlusNode :: Map { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Map { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Map { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: FlatMap { f : _ , input : deref!(HfPlusNode :: Persist (_)) , } => { if let HfPlusNode :: FlatMap { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: FlatMap { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Filter { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Filter { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Filter { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Network { input : box HfPlusNode :: Persist (_) , .. } => { if let HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Union (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Union (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Union (left , right))) ; } else { unreachable ! () } } HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: CrossProduct (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,) ,)))) ; } else { unreachable ! () } } HfPlusNode :: Join (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Join (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: Join (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,))))) ; } else { unreachable ! () } } _ => { } } } pub fn persist_pullup (ir : Vec < HfPlusLeaf >) -> Vec < HfPlusLeaf > { let mut seen_tees = Default :: default () ; let mut persist_pulled_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| n , s | persist_pullup_node (n , s , & mut persist_pulled_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn persist_pullup_through_map () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } # [test] fn persist_pullup_behind_tee () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; let before_tee = flow . source_iter (& process , q ! (0 .. 10)) . tick_batch () . persist () ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } } } pub mod profiler { pub use std :: cell :: RefCell ; pub use hydroflow :: futures :: channel :: mpsc :: UnboundedSender ; pub use stageleft :: * ; pub use crate as hydroflow_plus ; pub use crate :: ir :: * ; pub use crate :: RuntimeContext ; pub fn increment_counter (count : & mut u64) { * count += 1 ; } pub fn quoted_any_fn < 'a , F : Fn (& usize) + 'a , Q : IntoQuotedMut < 'a , F > > (q : Q) -> Q { q } # [doc = " Add a profiling node before each node to count the cardinality of its input"] pub fn add_profiling_node < 'a > (node : & mut HfPlusNode < 'a > , _context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > , id : & mut u32 , seen_tees : & mut SeenTees < 'a > ,) { let my_id = * id ; * id += 1 ; node . transform_children (| node , seen_tees | { add_profiling_node (node , _context , counters , counter_queue , id , seen_tees) } , seen_tees ,) ; let orig_node = std :: mem :: replace (node , HfPlusNode :: Placeholder) ; * node = HfPlusNode :: Inspect { f : quoted_any_fn (q ! ({ counter_queue . borrow () . unbounded_send ((my_id as usize , counters . borrow () [my_id as usize])) . unwrap () ; counters . borrow_mut () [my_id as usize] = 0 ; move | _ | { hydroflow_plus :: profiler :: increment_counter (& mut counters . borrow_mut () [my_id as usize] ,) ; } })) . splice () . into () , input : Box :: new (orig_node) , } } # [doc = " Count the cardinality of each input and periodically output to a file"] pub fn profiling < 'a > (ir : Vec < HfPlusLeaf < 'a > > , context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > ,) -> Vec < HfPlusLeaf < 'a > > { let mut id = 0 ; let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | { add_profiling_node (node , context , counters , counter_queue , & mut id , seen_tees) } , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn profiler_wrapping_all_operators () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let runtime_context = flow . runtime_context () ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (& built . ir ()) ; let counters = RuntimeData :: new ("Fake") ; let counter_queue = RuntimeData :: new ("Fake") ; let pushed_down = built . with_default_optimize () . optimize_with (| ir | super :: profiling (ir , runtime_context , counters , counter_queue)) ; insta :: assert_debug_snapshot ! (& pushed_down . ir ()) ; let _ = pushed_down . compile_no_network :: < MultiGraph > () ; } } } pub mod properties { pub use std :: collections :: HashSet ; pub use stageleft :: * ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , SeenTees } ; pub use crate :: properties :: PropertyDatabase ; # [doc = " Allows us to convert the hydroflow datatype for folds to a binary operation for the algebra"] # [doc = " property tests."] # [allow (dead_code)] pub fn convert_hf_to_binary < I , A : Default , F : Fn (& mut A , I) > (f : F) -> impl Fn (I , I) -> A { move | a , b | { let mut acc = Default :: default () ; f (& mut acc , a) ; f (& mut acc , b) ; acc } } # [cfg (stageleft_macro)] impl PropertyDatabase { # [doc = " Tags the expression as commutative."] pub fn add_commutative_tag < 'a , I , A , F : Fn (& mut A , I) , Q : Quoted < 'a , F > + Clone > (& mut self , expr : Q ,) -> Q { let expr_clone = expr . clone () ; self . commutative . insert (expr_clone . splice ()) ; expr } pub fn is_tagged_commutative (& self , expr : & syn :: Expr) -> bool { self . commutative . contains (expr) } } pub fn properties_optimize_node < 'a > (node : & mut HfPlusNode < 'a > , db : & PropertyDatabase , seen_tees : & mut SeenTees < 'a > ,) { node . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , seen_tees ,) ; match node { HfPlusNode :: ReduceKeyed { f , .. } if db . is_tagged_commutative (& f . 0) => { dbg ! ("IDENTIFIED COMMUTATIVE OPTIMIZATION for {:?}" , & f) ; } _ => { } } } pub fn properties_optimize < 'a > (ir : Vec < HfPlusLeaf < 'a > > , db : & PropertyDatabase ,) -> Vec < HfPlusLeaf < 'a > > { let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use super :: * ; use crate :: deploy :: SingleProcessGraph ; use crate :: FlowBuilder ; # [test] fn test_property_database () { let mut db = PropertyDatabase :: default () ; assert ! (! db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; let _ = db . add_commutative_tag (q ! (| a : & mut i32 , b : i32 | * a += b)) ; assert ! (db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; } # [test] fn test_property_optimized () { let flow = FlowBuilder :: new () ; let mut database = PropertyDatabase :: default () ; let process = flow . process :: < () > () ; let counter_func = q ! (| count : & mut i32 , _ | * count += 1) ; let _ = database . add_commutative_tag (counter_func) ; flow . source_iter (& process , q ! (vec ! [])) . map (q ! (| string : String | (string , ()))) . tick_batch () . fold_keyed (q ! (|| 0) , counter_func) . all_ticks () . for_each (q ! (| (string , count) | println ! ("{}: {}" , string , count))) ; let built = flow . finalize () . optimize_with (| ir | properties_optimize (ir , & database)) . with_default_optimize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let _ = built . compile_no_network :: < SingleProcessGraph > () ; } } } pub use crate :: RuntimeContext ; # [cfg (stageleft_macro)] impl Copy for RuntimeContext < '_ > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Context > for RuntimeContext < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (quote ! (& context))) } } pub use crate :: HfCompiled ; # [cfg (stageleft_macro)] impl < 'a , ID > HfCompiled < 'a , ID > { pub fn hydroflow_ir (& self) -> & BTreeMap < usize , HydroflowGraph > { & self . hydroflow_ir } } # [cfg (stageleft_macro)] impl < 'a > HfCompiled < 'a , usize > { pub fn with_dynamic_id (self , id : impl Quoted < 'a , usize >) -> HfBuiltWithId < 'a > { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; let mut conditioned_tokens = None ; for (subgraph_id , flat_graph) in self . hydroflow_ir { let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; let my_extra_stmts = self . extra_stmts . get (& subgraph_id) . cloned () . unwrap_or_default () ; if let Some (conditioned_tokens) = conditioned_tokens . as_mut () { * conditioned_tokens = syn :: parse_quote ! { # conditioned_tokens else if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } } ; } else { conditioned_tokens = Some (syn :: parse_quote ! { if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } }) ; } } let conditioned_tokens : TokenStream = conditioned_tokens . unwrap () ; let id = id . splice () ; HfBuiltWithId { tokens : syn :: parse_quote ! ({ let __given_id = # id ; # conditioned_tokens else { panic ! ("Invalid node id: {}" , __given_id) ; } }) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfCompiled < 'a , () > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfCompiled < 'a , () > { fn to_tokens (mut self) -> (Option < TokenStream > , Option < TokenStream >) { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; if self . hydroflow_ir . len () != 1 { panic ! ("Expected exactly one subgraph in the Hydroflow IR") ; } let flat_graph = self . hydroflow_ir . remove (& 0) . unwrap () ; let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; (None , Some (tokens)) } } pub use crate :: HfBuiltWithId ; # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfBuiltWithId < 'a > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfBuiltWithId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (self . tokens)) } }
[INFO] [stdout]   |
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] error: `box` patterns have been removed (feature `box_patterns`)
[INFO] [stdout]  --> /opt/rustwide/target/debug/build/hydroflow_plus/5672655b657d1e44/out/lib_pub.rs:1:93465
[INFO] [stdout]   |
[INFO] [stdout] 1 | ...ersist (_) , } => { if let HfPlusNode :: FlatMap { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: repl...
[INFO] [stdout]   |                                                                   ^^^
[INFO] [stdout]   |
[INFO] [stdout]   = help: enable feature `deref_patterns` instead and...
[INFO] [stdout] help: ...if possible just remove keyword `box`...
[INFO] [stdout]   |
[INFO] [stdout] 1 - pub use std :: collections :: BTreeMap ; pub use std :: marker :: PhantomData ; pub use hydroflow :: scheduled :: context :: Context ; pub use hydroflow :: scheduled :: graph :: Hydroflow ; pub use hydroflow :: * ; pub use lang :: graph :: { partition_graph , HydroflowGraph } ; pub use proc_macro2 :: TokenStream ; pub use quote :: quote ; pub use stageleft :: runtime_support :: FreeVariable ; pub use stageleft :: Quoted ; pub mod runtime_support { pub use bincode ; } pub mod stream { pub use std :: cell :: RefCell ; pub use std :: hash :: Hash ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow :: bytes :: Bytes ; pub use hydroflow :: futures :: Sink ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: quote ; pub use serde :: de :: DeserializeOwned ; pub use serde :: Serialize ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use syn :: parse_quote ; pub use crate :: builder :: { ClusterIds , FlowLeaves } ; pub use crate :: cycle :: { CycleCollection , CycleComplete } ; pub use crate :: ir :: { DebugInstantiate , HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { CanSend , Location , LocationId } ; pub use crate :: { Cluster , Optional , Singleton } ; pub use crate :: stream :: Unbounded ; pub use crate :: stream :: Bounded ; pub use crate :: stream :: NoTick ; pub use crate :: stream :: Tick ; pub use crate :: stream :: Stream ; # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Stream { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Stream < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Stream { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , C , N > > ,) -> Stream < 'a , (T , O) , W , C , N > where O : Clone , { let other : Optional < 'a , O , Bounded , C , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn cross_product < O > (self , other : Stream < 'a , O , W , C , N >) -> Stream < 'a , (T , O) , W , C , N > where T : Clone , O : Clone , { if self . location_kind != other . location_kind { panic ! ("cross_product must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossProduct (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn union (self , other : Stream < 'a , T , W , C , N >) -> Stream < 'a , T , W , C , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn dest_sink < S : Unpin + Sink < T > + 'a > (self , sink : impl Quoted < 'a , S >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: DestSink { sink : sink . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn first (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } # [doc = " Allow this stream through if the other stream has elements, otherwise the output is empty."] pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } # [doc = " Allow this stream through if the other stream is empty, otherwise the output is empty."] pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn enumerate (self) -> Stream < 'a , (usize , T) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Enumerate (Box :: new (self . ir_node . into_inner ())) ,) } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn sort (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Ord , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Sort (Box :: new (self . ir_node . into_inner ())) ,) } pub fn count (self) -> Singleton < 'a , usize , Bounded , Tick , N > { self . fold (q ! (|| 0usize) , q ! (| count , _ | * count += 1)) } pub fn delta (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } pub fn unique (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Eq + Hash , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unique (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn tick_batch (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_prefix (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { self . tick_batch () . persist () } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn for_each < F : Fn (T) + 'a > (self , f : impl IntoQuotedMut < 'a , F >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: ForEach { input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , f : f . splice () . into () , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Unbounded , NoTick , N > { pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . tick_batch () . continue_if (samples . first ()) . all_ticks () } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Unbounded , NoTick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , C , N : Location > Stream < 'a , T , Bounded , C , N > { pub fn filter_not_in (self , other : Stream < 'a , T , Bounded , C , N >) -> Stream < 'a , T , Bounded , C , N > where T : Eq + Hash , { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Difference (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Stream < 'a , & T , W , C , N > { pub fn cloned (self) -> Stream < 'a , T , W , C , N > { self . map (q ! (| d | d . clone ())) } } # [cfg (stageleft_macro)] impl < 'a , K , V1 , W , C , N : Location > Stream < 'a , (K , V1) , W , C , N > { pub fn join < W2 , V2 > (self , n : Stream < 'a , (K , V2) , W2 , C , N > ,) -> Stream < 'a , (K , (V1 , V2)) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Join (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } pub fn anti_join < W2 > (self , n : Stream < 'a , K , W2 , C , N >) -> Stream < 'a , (K , V1) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("anti_join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: AntiJoin (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , K : Eq + Hash , V , N : Location > Stream < 'a , (K , V) , Bounded , Tick , N > { pub fn fold_keyed < A , I : Fn () -> A + 'a , F : Fn (& mut A , V) + 'a > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , A) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FoldKeyed { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce_keyed < F : Fn (& mut V , V) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , V) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: ReduceKeyed { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } pub fn get_this_crate () -> TokenStream { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , Span :: call_site ()) ; quote ! { # ident } } } } pub fn serialize_bincode < T : Serialize > (is_demux : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if is_demux { parse_quote ! { map (| (id , data) | { (id , # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into ()) }) } } else { parse_quote ! { map (| data | { # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into () }) } } } pub fn deserialize_bincode < T : DeserializeOwned > (tagged : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if tagged { parse_quote ! { map (| res | { let (id , b) = res . unwrap () ; (id , # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& b) . unwrap ()) }) } } else { parse_quote ! { map (| res | { # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& res . unwrap ()) . unwrap () }) } } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn send_bincode < N2 : Location , CoreType > (self , other : & N2 ,) -> Stream < 'a , N :: Out < CoreType > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T > , CoreType : Serialize + DeserializeOwned , { let serialize_pipeline = Some (serialize_bincode :: < CoreType > (N :: is_demux ())) ; let deserialize_pipeline = Some (deserialize_bincode :: < CoreType > (N :: is_tagged ())) ; Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bytes < N2 : Location > (self , other : & N2 ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T > , { Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline : None , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline : if N :: is_tagged () { Some (parse_quote ! (map (| (id , b) | (id , b . unwrap () . freeze ())))) } else { Some (parse_quote ! (map (| b | b . unwrap () . freeze ()))) } , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bincode_interleaved < N2 : Location , Tag , CoreType > (self , other : & N2 ,) -> Stream < 'a , CoreType , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T , Out < CoreType > = (Tag , CoreType) > , CoreType : Serialize + DeserializeOwned , { self . send_bincode :: < N2 , CoreType > (other) . map (q ! (| (_ , b) | b)) } pub fn send_bytes_interleaved < N2 : Location , Tag > (self , other : & N2 ,) -> Stream < 'a , Bytes , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T , Out < Bytes > = (Tag , Bytes) > , { self . send_bytes :: < N2 > (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bincode < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < T > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) > , T : Clone + Serialize + DeserializeOwned , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bincode (other) } pub fn broadcast_bincode_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , T , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) , Out < T > = (Tag , T) > + 'a , T : Clone + Serialize + DeserializeOwned , { self . broadcast_bincode (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bytes < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) > + 'a , T : Clone , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bytes (other) } pub fn broadcast_bytes_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , Bytes , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) , Out < Bytes > = (Tag , Bytes) > + 'a , T : Clone , { self . broadcast_bytes (other) . map (q ! (| (_ , b) | b)) } } } pub use stream :: { Bounded , NoTick , Stream , Tick , Unbounded } ; pub mod singleton { pub use std :: cell :: RefCell ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use crate :: builder :: FlowLeaves ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial , CycleComplete } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: Stream ; pub use crate :: singleton :: CrossResult ; # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Singleton < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Singleton :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } pub use crate :: singleton :: Singleton ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Singleton { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleComplete < 'a > for Singleton < 'a , T , Bounded , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleCollectionWithInitial < 'a > for Singleton < 'a , T , Bounded , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , initial : Self , l : LocationId ,) -> Self { Singleton :: new (l , ir_leaves , HfPlusNode :: Union (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , }) , initial . ir_node . into_inner () . into () ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Singleton < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Singleton { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , U , W , C , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (Self :: other_ir_node (other)) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Singleton < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CrossSingleton (Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , Box :: new (HfPlusNode :: Unpersist (Box :: new (Self :: other_ir_node (other)))) ,))) ,) } } pub use crate :: singleton :: Optional ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Optional { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } pub fn some (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: new (singleton . location_kind , singleton . ir_leaves , singleton . ir_node . into_inner () ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > From < Singleton < 'a , T , W , C , N > > for Optional < 'a , T , W , C , N > { fn from (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: some (singleton) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Optional < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Optional { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn into_stream (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , Tick , N > > ,) -> Optional < 'a , (T , O) , Bounded , Tick , N > where O : Clone , { let other : Optional < 'a , O , Bounded , Tick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn union (self , other : Optional < 'a , T , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Optional < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_samples (self) -> Stream < 'a , T , Unbounded , NoTick , N > { self . latest_tick () . all_ticks () } pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . latest_tick () . continue_if (samples . first ()) . latest () . tick_samples () } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Unbounded , NoTick , N > > ,) -> Optional < 'a , (T , O) , Unbounded , NoTick , N > where O : Clone , { let other : Optional < 'a , O , Unbounded , NoTick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } self . latest_tick () . cross_singleton (other . latest_tick ()) . latest () } } } pub use singleton :: { Optional , Singleton } ; pub mod location { pub use std :: marker :: PhantomData ; pub use crate :: location :: LocationId ; pub use crate :: location :: Location ; pub use crate :: location :: Process ; # [cfg (stageleft_macro)] impl < P > Clone for Process < P > { fn clone (& self) -> Self { Process { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < P > Location for Process < P > { fn id (& self) -> LocationId { LocationId :: Process (self . id) } } pub use crate :: location :: Cluster ; # [cfg (stageleft_macro)] impl < C > Clone for Cluster < C > { fn clone (& self) -> Self { Cluster { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < C > Location for Cluster < C > { fn id (& self) -> LocationId { LocationId :: Cluster (self . id) } } pub use crate :: location :: CanSend ; # [cfg (stageleft_macro)] impl < P1 , P2 > CanSend < Process < P2 > > for Process < P1 > { type In < T > = T ; type Out < T > = T ; fn is_demux () -> bool { false } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < P1 , C2 > CanSend < Cluster < C2 > > for Process < P1 > { type In < T > = (u32 , T) ; type Out < T > = T ; fn is_demux () -> bool { true } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < C1 , P2 > CanSend < Process < P2 > > for Cluster < C1 > { type In < T > = T ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { false } fn is_tagged () -> bool { true } } # [cfg (stageleft_macro)] impl < C1 , C2 > CanSend < Cluster < C2 > > for Cluster < C1 > { type In < T > = (u32 , T) ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { true } fn is_tagged () -> bool { true } } } pub use location :: { Cluster , Process } ; pub mod deploy { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use stageleft :: Quoted ; pub mod graphs { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use super :: { LocalDeploy , Node , ProcessSpec } ; pub use crate :: deploy :: graphs :: SingleProcessGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for SingleProcessGraph { type Process = SingleNode ; type Cluster = SingleNode ; type Meta = () ; type GraphId = () ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { SingleNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { SingleNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , SingleProcessGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> SingleNode { SingleNode { } } } pub use crate :: deploy :: graphs :: SingleNode ; # [cfg (stageleft_macro)] impl Node for SingleNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } pub use crate :: deploy :: graphs :: MultiGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for MultiGraph { type Process = MultiNode ; type Cluster = MultiNode ; type Meta = () ; type GraphId = usize ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { MultiNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { MultiNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , MultiGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> MultiNode { MultiNode { } } } pub use crate :: deploy :: graphs :: MultiNode ; # [cfg (stageleft_macro)] impl Node for MultiNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } } pub use graphs :: * ; pub use crate :: deploy :: LocalDeploy ; pub use crate :: deploy :: Deploy ; # [cfg (stageleft_macro)] impl < 'a , T : Deploy < 'a , Process = N , Cluster = C , Meta = M , GraphId = R > , N : Node < Meta = M > , C : Node < Meta = M > , M : Default , R , > LocalDeploy < 'a > for T { type Process = N ; type Cluster = C ; type Meta = M ; type GraphId = R ; fn has_trivial_node () -> bool { < T as Deploy < 'a > > :: has_trivial_node () } fn trivial_process (id : usize) -> Self :: Process { < T as Deploy < 'a > > :: trivial_process (id) } fn trivial_cluster (id : usize) -> Self :: Cluster { < T as Deploy < 'a > > :: trivail_cluster (id) } } pub use crate :: deploy :: ProcessSpec ; pub use crate :: deploy :: ClusterSpec ; pub use crate :: deploy :: Node ; } pub use deploy :: { ClusterSpec , Deploy , ProcessSpec } ; pub mod cycle { pub use std :: marker :: PhantomData ; pub use crate :: builder :: FlowLeaves ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: cycle :: CycleComplete ; pub use crate :: cycle :: CycleCollection ; pub use crate :: cycle :: CycleCollectionWithInitial ; pub use crate :: cycle :: HfCycle ; # [cfg (stageleft_macro)] impl < 'a , S : CycleComplete < 'a > > HfCycle < 'a , S > { pub fn complete (self , stream : S) { let ident = self . ident ; S :: complete (stream , ident) } } } pub use cycle :: HfCycle ; pub mod builder { pub use std :: cell :: RefCell ; pub use std :: collections :: HashMap ; pub use std :: marker :: PhantomData ; pub use std :: rc :: Rc ; pub use std :: time :: Duration ; pub use hydroflow :: futures :: stream :: Stream as FuturesStream ; pub use hydroflow :: { tokio , tokio_stream } ; pub use internal :: TokenStream ; pub use proc_macro2 :: Span ; pub use quote :: quote ; pub use runtime_support :: FreeVariable ; pub use stageleft :: * ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Cluster , Location , LocationId , Process } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: { HfCycle , Optional , RuntimeContext , Singleton , Stream } ; pub mod built { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use hydroflow_lang :: graph :: { eliminate_extra_unions_tees , HydroflowGraph } ; pub use super :: deploy :: { DeployFlow , DeployResult } ; pub use crate :: deploy :: { ClusterSpec , Deploy , LocalDeploy , ProcessSpec } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Cluster , Process } ; pub use crate :: HfCompiled ; pub use crate :: builder :: built :: BuiltFlow ; # [cfg (stageleft_macro)] impl < 'a > Drop for BuiltFlow < 'a > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped BuiltFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn ir (& self) -> & Vec < HfPlusLeaf < 'a > > { & self . ir } pub fn optimize_with (mut self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> BuiltFlow < 'a > { self . used = true ; BuiltFlow { ir : f (std :: mem :: take (& mut self . ir)) , processes : std :: mem :: take (& mut self . processes) , clusters : std :: mem :: take (& mut self . clusters) , used : false , _phantom : PhantomData , } } } pub fn build_inner (ir : & mut Vec < HfPlusLeaf >) -> BTreeMap < usize , HydroflowGraph > { let mut builders = BTreeMap :: new () ; let mut built_tees = HashMap :: new () ; let mut next_stmt_id = 0 ; for leaf in ir { leaf . emit (& mut builders , & mut built_tees , & mut next_stmt_id) ; } builders . into_iter () . map (| (k , v) | { let (mut flat_graph , _ , _) = v . build () ; eliminate_extra_unions_tees (& mut flat_graph) ; (k , flat_graph) }) . collect () } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn compile_no_network < D : LocalDeploy < 'a > > (mut self) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; HfCompiled { hydroflow_ir : build_inner (& mut self . ir) , extra_stmts : BTreeMap :: new () , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> BuiltFlow < 'a > { self . optimize_with (crate :: persist_pullup :: persist_pullup) } fn into_deploy < D : LocalDeploy < 'a > > (mut self) -> DeployFlow < 'a , D > { self . used = true ; let processes = if D :: has_trivial_node () { self . processes . iter () . map (| id | (* id , D :: trivial_process (* id))) . collect () } else { HashMap :: new () } ; let clusters = if D :: has_trivial_node () { self . clusters . iter () . map (| id | (* id , D :: trivial_cluster (* id))) . collect () } else { HashMap :: new () } ; DeployFlow { ir : std :: mem :: take (& mut self . ir) , nodes : processes , clusters , used : false , _phantom : PhantomData , } } pub fn with_process < P , D : LocalDeploy < 'a > > (self , process : & Process < P > , spec : impl ProcessSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_process (process , spec) } pub fn with_cluster < C , D : LocalDeploy < 'a > > (self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_cluster (cluster , spec) } pub fn compile < D : Deploy < 'a > + 'a > (self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . into_deploy :: < D > () . compile (env) } pub fn deploy < D : Deploy < 'a , CompileEnv = () > + 'a > (self , env : & mut D :: InstantiateEnv ,) -> DeployResult < 'a , D > { self . into_deploy :: < D > () . deploy (env) } } } pub mod deploy { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use proc_macro2 :: Span ; pub use stageleft :: Quoted ; pub use super :: built :: build_inner ; pub use crate :: deploy :: { LocalDeploy , Node } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: { Cluster , ClusterSpec , Deploy , HfCompiled , Process , ProcessSpec } ; pub use crate :: builder :: deploy :: DeployFlow ; # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > Drop for DeployFlow < 'a , D > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped DeployFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > DeployFlow < 'a , D > { pub fn with_process < P > (mut self , process : & Process < P > , spec : impl ProcessSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < P > () . to_string () ; self . nodes . insert (process . id , spec . build (process . id , & tag_name)) ; self } pub fn with_cluster < C > (mut self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < C > () . to_string () ; self . clusters . insert (cluster . id , spec . build (cluster . id , & tag_name)) ; self } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployFlow < 'a , D > { pub fn compile (mut self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; let mut seen_tees : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | leaf . compile_network :: < D > (env , & mut seen_tees , & self . nodes , & self . clusters)) . collect () ; let extra_stmts = self . extra_stmts (env) ; HfCompiled { hydroflow_ir : build_inner (& mut ir_leaves_networked) , extra_stmts , _phantom : PhantomData , } } fn extra_stmts (& self , env : & < D as Deploy < 'a > > :: CompileEnv) -> BTreeMap < usize , Vec < syn :: Stmt > > { let all_locations_count = self . nodes . len () + self . clusters . len () ; let mut extra_stmts : BTreeMap < usize , Vec < syn :: Stmt > > = BTreeMap :: new () ; for & c_id in self . clusters . keys () { let self_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , c_id) , Span :: call_site () ,) ; let self_id_expr = D :: cluster_self_id (env) . splice () ; extra_stmts . entry (c_id) . or_default () . push (syn :: parse_quote ! { let # self_id_ident = # self_id_expr ; }) ; for other_location in 0 .. all_locations_count { let other_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , c_id) , Span :: call_site () ,) ; let other_id_expr = D :: cluster_ids (env , c_id) . splice () ; extra_stmts . entry (other_location) . or_default () . push (syn :: parse_quote ! { let # other_id_ident = # other_id_expr ; }) ; } } extra_stmts } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a , CompileEnv = () > > DeployFlow < 'a , D > { # [must_use] pub fn deploy (mut self , env : & mut D :: InstantiateEnv) -> DeployResult < 'a , D > { self . used = true ; let mut seen_tees_instantiate : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | { leaf . compile_network :: < D > (& () , & mut seen_tees_instantiate , & self . nodes , & self . clusters ,) }) . collect () ; let mut compiled = build_inner (& mut ir_leaves_networked) ; let mut extra_stmts = self . extra_stmts (& ()) ; let mut meta = D :: Meta :: default () ; let (mut processes , mut clusters) = (std :: mem :: take (& mut self . nodes) . into_iter () . map (| (node_id , node) | { node . instantiate (env , & mut meta , compiled . remove (& node_id) . unwrap () , extra_stmts . remove (& node_id) . unwrap_or_default () ,) ; (node_id , node) }) . collect :: < HashMap < _ , _ > > () , std :: mem :: take (& mut self . clusters) . into_iter () . map (| (cluster_id , cluster) | { cluster . instantiate (env , & mut meta , compiled . remove (& cluster_id) . unwrap () , extra_stmts . remove (& cluster_id) . unwrap_or_default () ,) ; (cluster_id , cluster) }) . collect :: < HashMap < _ , _ > > () ,) ; for node in processes . values_mut () { node . update_meta (& meta) ; } for cluster in clusters . values_mut () { cluster . update_meta (& meta) ; } let mut seen_tees_connect = HashMap :: new () ; for leaf in ir_leaves_networked { leaf . connect_network (& mut seen_tees_connect) ; } DeployResult { processes , clusters , } } } pub use crate :: builder :: deploy :: DeployResult ; # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployResult < 'a , D > { pub fn get_process < P > (& self , p : & Process < P >) -> & D :: Process { let id = match p . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . processes . get (& id) . unwrap () } pub fn get_cluster < C > (& self , c : & Cluster < C >) -> & D :: Cluster { let id = match c . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . clusters . get (& id) . unwrap () } } } # [doc = " Tracks the leaves of the dataflow IR. This is referenced by"] # [doc = " `Stream` and `HfCycle` to build the IR. The inner option will"] # [doc = " be set to `None` when this builder is finalized."] pub type FlowLeaves < 'a > = Rc < RefCell < Option < Vec < HfPlusLeaf < 'a > > > > > ; pub use crate :: builder :: ClusterIds ; # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Vec < u32 > > for ClusterIds < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , & 'a Vec < u32 > > for ClusterIds < 'a > { } # [derive (Copy , Clone)] pub struct ClusterSelfId < 'a > { pub id : usize , pub _phantom : PhantomData < & 'a mut & 'a u32 > , } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < u32 > for ClusterSelfId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , u32 > for ClusterSelfId < 'a > { } pub use crate :: builder :: FlowBuilder ; # [cfg (stageleft_macro)] impl < 'a > Drop for FlowBuilder < 'a > { fn drop (& mut self) { if ! self . finalized { panic ! ("Dropped FlowBuilder without finalizing, you may have forgotten to call `with_default_optimize`, `optimize_with`, or `finalize`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > QuotedContext for FlowBuilder < 'a > { fn create () -> Self { FlowBuilder :: new () } } # [cfg (stageleft_macro)] impl < 'a > FlowBuilder < 'a > { # [allow (clippy :: new_without_default)] pub fn new () -> FlowBuilder < 'a > { FlowBuilder { ir_leaves : Rc :: new (RefCell :: new (Some (Vec :: new ()))) , nodes : RefCell :: new (vec ! []) , clusters : RefCell :: new (vec ! []) , cycle_ids : RefCell :: new (HashMap :: new ()) , next_node_id : RefCell :: new (0) , finalized : false , _phantom : PhantomData , } } pub fn finalize (mut self) -> built :: BuiltFlow < 'a > { self . finalized = true ; built :: BuiltFlow { ir : self . ir_leaves . borrow_mut () . take () . unwrap () , processes : self . nodes . replace (vec ! []) , clusters : self . clusters . replace (vec ! []) , used : false , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> built :: BuiltFlow < 'a > { self . finalize () . with_default_optimize () } pub fn optimize_with (self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> built :: BuiltFlow < 'a > { self . finalize () . optimize_with (f) } pub fn ir_leaves (& self) -> & FlowLeaves < 'a > { & self . ir_leaves } pub fn process < P > (& self) -> Process < P > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . nodes . borrow_mut () . push (id) ; Process { id , _phantom : PhantomData , } } pub fn cluster < C > (& self) -> Cluster < C > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . clusters . borrow_mut () . push (id) ; Cluster { id , _phantom : PhantomData , } } pub fn runtime_context (& self) -> RuntimeContext < 'a > { RuntimeContext { _phantom : PhantomData , } } pub fn cluster_members < C > (& self , cluster : & Cluster < C > ,) -> impl Quoted < 'a , & 'a Vec < u32 > > + Copy + 'a { ClusterIds { id : cluster . id , _phantom : PhantomData , } } pub fn cluster_self_id < C > (& self , cluster : & Cluster < C >) -> impl Quoted < 'a , u32 > + Copy + 'a { ClusterSelfId { id : cluster . id , _phantom : PhantomData , } } pub fn spin < L : Location > (& self , on : & L) -> Stream < 'a , () , Unbounded , NoTick , L > { Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Spin () , location_kind : on . id () , })) ,) } pub fn spin_batch < L : Location > (& self , on : & L , batch_size : impl Quoted < 'a , usize > + Copy + 'a ,) -> Stream < 'a , () , Bounded , Tick , L > { self . spin (on) . flat_map (q ! (move | _ | 0 .. batch_size)) . map (q ! (| _ | ())) . tick_batch () } pub fn source_stream < T , E : FuturesStream < Item = T > + Unpin , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Unbounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Stream (e . into ()) , location_kind : on . id () , })) ,) } pub fn source_iter < T , E : IntoIterator < Item = T > , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Bounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , })) ,) } pub fn singleton < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Singleton < 'a , T , Bounded , NoTick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Singleton :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,)))) ,) } pub fn singleton_first_tick < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Optional < 'a , T , Bounded , Tick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,) } pub fn source_interval < L : Location > (& self , on : & L , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , () , Unbounded , NoTick , L > { let interval = interval . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : on . id () , })) ,) } pub fn source_interval_delayed < L : Location > (& self , on : & L , delay : impl Quoted < 'a , Duration > + Copy + 'a , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , tokio :: time :: Instant , Unbounded , NoTick , L > { self . source_stream (on , q ! (tokio_stream :: wrappers :: IntervalStream :: new (tokio :: time :: interval_at (tokio :: time :: Instant :: now () + delay , interval))) ,) . tick_batch () . first () . latest () } pub fn cycle < S : CycleCollection < 'a > > (& self , on : & S :: Location) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , on . id ()) ,) } pub fn cycle_with_initial < S : CycleCollectionWithInitial < 'a > > (& self , on : & S :: Location , initial : S ,) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , initial , on . id ()) ,) } } } pub use builder :: FlowBuilder ; pub mod ir { pub use core :: panic ; pub use std :: cell :: RefCell ; pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow_lang :: graph :: FlatGraphBuilder ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: ToTokens ; pub use syn :: parse_quote ; pub use crate :: deploy :: Deploy ; pub use crate :: location :: LocationId ; pub use crate :: ir :: DebugExpr ; # [cfg (stageleft_macro)] impl From < syn :: Expr > for DebugExpr { fn from (expr : syn :: Expr) -> DebugExpr { DebugExpr (expr) } } # [cfg (stageleft_macro)] impl Deref for DebugExpr { type Target = syn :: Expr ; fn deref (& self) -> & Self :: Target { & self . 0 } } # [cfg (stageleft_macro)] impl ToTokens for DebugExpr { fn to_tokens (& self , tokens : & mut TokenStream) { self . 0 . to_tokens (tokens) ; } } # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugExpr { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "{}" , self . 0 . to_token_stream ()) } } pub use crate :: ir :: DebugInstantiate ; # [cfg (stageleft_macro)] impl < 'a > std :: fmt :: Debug for DebugInstantiate < 'a > { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<network instantiate>") } } pub use crate :: ir :: DebugPipelineFn ; # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugPipelineFn { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<function>") } } pub use crate :: ir :: HfPlusSource ; pub use crate :: ir :: HfPlusLeaf ; # [cfg (stageleft_macro)] impl < 'a > HfPlusLeaf < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . compile_network :: < D > (compile_env , s , nodes , clusters) ; } , seen_tees ,) } pub fn connect_network (self , seen_tees : & mut SeenTees < 'a >) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . connect_network (s) ; } , seen_tees ,) } pub fn transform_children (self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) -> HfPlusLeaf < 'a > { match self { HfPlusLeaf :: ForEach { f , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: ForEach { f , input } } HfPlusLeaf :: DestSink { sink , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: DestSink { sink , input } } HfPlusLeaf :: CycleSink { ident , location_kind , mut input , } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: CycleSink { ident , location_kind , input , } } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) { match self { HfPlusLeaf :: ForEach { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> for_each (# f) ; }) ; } HfPlusLeaf :: DestSink { sink , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink) ; }) ; } HfPlusLeaf :: CycleSink { ident , location_kind , input , } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; assert_eq ! (input_location_id , * location_id , "cycle_sink location mismatch") ; graph_builders . entry (* location_id) . or_default () . add_statement (parse_quote ! { # ident = # input_ident ; }) ; } } } } pub use crate :: ir :: HfPlusNode ; pub type SeenTees < 'a > = HashMap < * const RefCell < HfPlusNode < 'a > > , Rc < RefCell < HfPlusNode < 'a > > > > ; # [cfg (stageleft_macro)] impl < 'a > HfPlusNode < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (& mut self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) { self . transform_children (| n , s | n . compile_network :: < D > (compile_env , s , nodes , clusters) , seen_tees ,) ; if let HfPlusNode :: Network { from_location , to_location , instantiate_fn , .. } = self { let (sink_expr , source_expr , connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { let ((sink , source) , connect_fn) = match (from_location , to_location) { (LocationId :: Process (from) , LocationId :: Process (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: o2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Process (from) , LocationId :: Cluster (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: o2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Process (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: m2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Cluster (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: m2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } } ; (sink , source , connect_fn) } DebugInstantiate :: Finalized (_ , _ , _) => panic ! ("network already finalized") , } ; * instantiate_fn = DebugInstantiate :: Finalized (sink_expr , source_expr , connect_fn) ; } } pub fn connect_network (& mut self , seen_tees : & mut SeenTees < 'a >) { self . transform_children (| n , s | n . connect_network (s) , seen_tees) ; if let HfPlusNode :: Network { instantiate_fn , .. } = self { match instantiate_fn { DebugInstantiate :: Building () => panic ! ("network not built") , DebugInstantiate :: Finalized (_ , _ , ref connect_fn) => { connect_fn () ; } } } } pub fn transform_children (& mut self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) { match self { HfPlusNode :: Placeholder => { panic ! () ; } HfPlusNode :: Source { .. } => { } HfPlusNode :: CycleSource { .. } => { } HfPlusNode :: Tee { inner } => { if let Some (transformed) = seen_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { * inner = transformed . clone () ; } else { let transformed_cell = Rc :: new (RefCell :: new (HfPlusNode :: Placeholder)) ; seen_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , transformed_cell . clone () ,) ; let mut orig = inner . replace (HfPlusNode :: Placeholder) ; transform (& mut orig , seen_tees) ; * transformed_cell . borrow_mut () = orig ; * inner = transformed_cell ; } } HfPlusNode :: Persist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Unpersist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Delta (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Union (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossProduct (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossSingleton (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Join (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Difference (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: AntiJoin (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Map { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FlatMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Filter { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FilterMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Sort (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: DeferTick (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Enumerate (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Inspect { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Unique (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Fold { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FoldKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Reduce { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: ReduceKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Network { input , .. } => { transform (input . as_mut () , seen_tees) ; } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) -> (syn :: Ident , usize) { match self { HfPlusNode :: Placeholder => { panic ! () } HfPlusNode :: Persist (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let persist_id = * next_stmt_id ; * next_stmt_id += 1 ; let persist_ident = syn :: Ident :: new (& format ! ("stream_{}" , persist_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # persist_ident = # inner_ident -> persist ::<'static > () ; }) ; (persist_ident , location) } HfPlusNode :: Unpersist (_) => { panic ! ("Unpersist is a marker node and should have been optimized away. This is likely a compiler bug.") } HfPlusNode :: Delta (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let delta_id = * next_stmt_id ; * next_stmt_id += 1 ; let delta_ident = syn :: Ident :: new (& format ! ("stream_{}" , delta_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # delta_ident = # inner_ident -> multiset_delta () ; }) ; (delta_ident , location) } HfPlusNode :: Source { source , location_kind , } => { let source_id = * next_stmt_id ; * next_stmt_id += 1 ; let source_ident = syn :: Ident :: new (& format ! ("stream_{}" , source_id) , Span :: call_site ()) ; let source_stmt = match source { HfPlusSource :: Stream (expr) => { parse_quote ! { # source_ident = source_stream (# expr) ; } } HfPlusSource :: Iter (expr) => { parse_quote ! { # source_ident = source_iter (# expr) ; } } HfPlusSource :: Interval (expr) => { parse_quote ! { # source_ident = source_interval (# expr) ; } } HfPlusSource :: Spin () => { parse_quote ! { # source_ident = spin () ; } } } ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; graph_builders . entry (* location_id) . or_default () . add_statement (source_stmt) ; (source_ident , * location_id) } HfPlusNode :: CycleSource { ident , location_kind , } => { let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; (ident . clone () , * location_id) } HfPlusNode :: Tee { inner } => { if let Some (ret) = built_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { ret . clone () } else { let (inner_ident , inner_location_id) = inner . borrow () . emit (graph_builders , built_tees , next_stmt_id) ; let tee_id = * next_stmt_id ; * next_stmt_id += 1 ; let tee_ident = syn :: Ident :: new (& format ! ("stream_{}" , tee_id) , Span :: call_site ()) ; let builder = graph_builders . entry (inner_location_id) . or_default () ; builder . add_statement (parse_quote ! { # tee_ident = # inner_ident -> tee () ; }) ; built_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , (tee_ident . clone () , inner_location_id) ,) ; (tee_ident , inner_location_id) } } HfPlusNode :: Union (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "union inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let union_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # union_ident = union () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [0] # union_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # union_ident ; }) ; (union_ident , left_location_id) } HfPlusNode :: CrossSingleton (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "cross_singleton inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let cross_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # cross_ident = cross_singleton () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [input] # cross_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [single] # cross_ident ; }) ; (cross_ident , left_location_id) } HfPlusNode :: CrossProduct (..) | HfPlusNode :: Join (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: CrossProduct (..)) { parse_quote ! (cross_join_multiset) } else { parse_quote ! (join_multiset) } ; let (HfPlusNode :: CrossProduct (left , right) | HfPlusNode :: Join (left , right)) = self else { unreachable ! () } ; let (left_inner , left_was_persist) = if let HfPlusNode :: Persist (left) = left . as_ref () { (left , true) } else { (left , false) } ; let (right_inner , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left_inner . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right_inner . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "join / cross product inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; match (left_was_persist , right_was_persist) { (true , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'static > () ; }) ; } (true , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'tick > () ; }) ; } (false , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } (false , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } } ; builder . add_statement (parse_quote ! { # left_ident -> [0] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Difference (..) | HfPlusNode :: AntiJoin (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Difference (..)) { parse_quote ! (difference_multiset) } else { parse_quote ! (anti_join_multiset) } ; let (HfPlusNode :: Difference (left , right) | HfPlusNode :: AntiJoin (left , right)) = self else { unreachable ! () } ; let (right , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "difference / anti join inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; if right_was_persist { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } else { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } builder . add_statement (parse_quote ! { # left_ident -> [pos] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [neg] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Map { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let map_id = * next_stmt_id ; * next_stmt_id += 1 ; let map_ident = syn :: Ident :: new (& format ! ("stream_{}" , map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # map_ident = # input_ident -> map (# f) ; }) ; (map_ident , input_location_id) } HfPlusNode :: FlatMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let flat_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let flat_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , flat_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # flat_map_ident = # input_ident -> flat_map (# f) ; }) ; (flat_map_ident , input_location_id) } HfPlusNode :: Filter { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_ident = # input_ident -> filter (# f) ; }) ; (filter_ident , input_location_id) } HfPlusNode :: FilterMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_map_ident = # input_ident -> filter_map (# f) ; }) ; (filter_map_ident , input_location_id) } HfPlusNode :: Sort (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sort_id = * next_stmt_id ; * next_stmt_id += 1 ; let sort_ident = syn :: Ident :: new (& format ! ("stream_{}" , sort_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # sort_ident = # input_ident -> sort () ; }) ; (sort_ident , input_location_id) } HfPlusNode :: DeferTick (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let defer_tick_id = * next_stmt_id ; * next_stmt_id += 1 ; let defer_tick_ident = syn :: Ident :: new (& format ! ("stream_{}" , defer_tick_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # defer_tick_ident = # input_ident -> defer_tick_lazy () ; }) ; (defer_tick_ident , input_location_id) } HfPlusNode :: Enumerate (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let enumerate_id = * next_stmt_id ; * next_stmt_id += 1 ; let enumerate_ident = syn :: Ident :: new (& format ! ("stream_{}" , enumerate_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # enumerate_ident = # input_ident -> enumerate () ; }) ; (enumerate_ident , input_location_id) } HfPlusNode :: Inspect { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let inspect_id = * next_stmt_id ; * next_stmt_id += 1 ; let inspect_ident = syn :: Ident :: new (& format ! ("stream_{}" , inspect_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # inspect_ident = # input_ident -> inspect (# f) ; }) ; (inspect_ident , input_location_id) } HfPlusNode :: Unique (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let unique_id = * next_stmt_id ; * next_stmt_id += 1 ; let unique_ident = syn :: Ident :: new (& format ! ("stream_{}" , unique_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # unique_ident = # input_ident -> unique ::<'tick > () ; }) ; (unique_ident , input_location_id) } HfPlusNode :: Fold { .. } | HfPlusNode :: FoldKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Fold { .. }) { parse_quote ! (fold) } else { parse_quote ! (fold_keyed) } ; let (HfPlusNode :: Fold { init , acc , input } | HfPlusNode :: FoldKeyed { init , acc , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let fold_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'static > (# init , # acc) ; }) ; } else { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'tick > (# init , # acc) ; }) ; } (fold_ident , input_location_id) } HfPlusNode :: Reduce { .. } | HfPlusNode :: ReduceKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Reduce { .. }) { parse_quote ! (reduce) } else { parse_quote ! (reduce_keyed) } ; let (HfPlusNode :: Reduce { f , input } | HfPlusNode :: ReduceKeyed { f , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let reduce_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'static > (# f) ; }) ; } else { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'tick > (# f) ; }) ; } (reduce_ident , input_location_id) } HfPlusNode :: Network { from_location : _ , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input , } => { let (sink_expr , source_expr , _connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { panic ! ("Expected the network to be finalized") } DebugInstantiate :: Finalized (sink , source , connect_fn) => { (sink , source , connect_fn) } } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sender_builder = graph_builders . entry (input_location_id) . or_default () ; if let Some (serialize_pipeline) = serialize_pipeline { sender_builder . add_statement (parse_quote ! { # input_ident -> # serialize_pipeline -> dest_sink (# sink_expr) ; }) ; } else { sender_builder . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink_expr) ; }) ; } let to_id = match to_location { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let receiver_builder = graph_builders . entry (* to_id) . or_default () ; let receiver_stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let receiver_stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , receiver_stream_id) , Span :: call_site ()) ; if let Some (deserialize_pipeline) = deserialize_pipeline { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) -> # deserialize_pipeline ; }) ; } else { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) ; }) ; } (receiver_stream_ident , * to_id) } } } } } pub mod persist_pullup { pub use std :: cell :: RefCell ; pub use std :: collections :: HashSet ; pub use std :: ops :: Deref ; pub use crate :: ir :: * ; pub fn persist_pullup_node < 'a > (node : & mut HfPlusNode < 'a > , seen_tees : & mut SeenTees < 'a > , persist_pulled_tees : & mut HashSet < * const RefCell < HfPlusNode < 'a > > > ,) { node . transform_children (| n , s | persist_pullup_node (n , s , persist_pulled_tees) , seen_tees ,) ; match node { HfPlusNode :: Unpersist (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Unpersist (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Delta (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Delta (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Tee { inner } => { if persist_pulled_tees . contains (& (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >)) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } else { let inner_borrow = inner . borrow () ; if let HfPlusNode :: Persist (_) = inner_borrow . deref () { drop (inner_borrow) ; persist_pulled_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >) ; if let HfPlusNode :: Persist (box behind_persist) = inner . replace (HfPlusNode :: Placeholder) { * inner . borrow_mut () = behind_persist ; } else { unreachable ! () } * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } } } HfPlusNode :: Map { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Map { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Map { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: FlatMap { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: FlatMap { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: FlatMap { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Filter { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Filter { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Filter { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Network { input : box HfPlusNode :: Persist (_) , .. } => { if let HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Union (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Union (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Union (left , right))) ; } else { unreachable ! () } } HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: CrossProduct (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,) ,)))) ; } else { unreachable ! () } } HfPlusNode :: Join (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Join (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: Join (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,))))) ; } else { unreachable ! () } } _ => { } } } pub fn persist_pullup (ir : Vec < HfPlusLeaf >) -> Vec < HfPlusLeaf > { let mut seen_tees = Default :: default () ; let mut persist_pulled_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| n , s | persist_pullup_node (n , s , & mut persist_pulled_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn persist_pullup_through_map () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } # [test] fn persist_pullup_behind_tee () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; let before_tee = flow . source_iter (& process , q ! (0 .. 10)) . tick_batch () . persist () ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } } } pub mod profiler { pub use std :: cell :: RefCell ; pub use hydroflow :: futures :: channel :: mpsc :: UnboundedSender ; pub use stageleft :: * ; pub use crate as hydroflow_plus ; pub use crate :: ir :: * ; pub use crate :: RuntimeContext ; pub fn increment_counter (count : & mut u64) { * count += 1 ; } pub fn quoted_any_fn < 'a , F : Fn (& usize) + 'a , Q : IntoQuotedMut < 'a , F > > (q : Q) -> Q { q } # [doc = " Add a profiling node before each node to count the cardinality of its input"] pub fn add_profiling_node < 'a > (node : & mut HfPlusNode < 'a > , _context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > , id : & mut u32 , seen_tees : & mut SeenTees < 'a > ,) { let my_id = * id ; * id += 1 ; node . transform_children (| node , seen_tees | { add_profiling_node (node , _context , counters , counter_queue , id , seen_tees) } , seen_tees ,) ; let orig_node = std :: mem :: replace (node , HfPlusNode :: Placeholder) ; * node = HfPlusNode :: Inspect { f : quoted_any_fn (q ! ({ counter_queue . borrow () . unbounded_send ((my_id as usize , counters . borrow () [my_id as usize])) . unwrap () ; counters . borrow_mut () [my_id as usize] = 0 ; move | _ | { hydroflow_plus :: profiler :: increment_counter (& mut counters . borrow_mut () [my_id as usize] ,) ; } })) . splice () . into () , input : Box :: new (orig_node) , } } # [doc = " Count the cardinality of each input and periodically output to a file"] pub fn profiling < 'a > (ir : Vec < HfPlusLeaf < 'a > > , context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > ,) -> Vec < HfPlusLeaf < 'a > > { let mut id = 0 ; let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | { add_profiling_node (node , context , counters , counter_queue , & mut id , seen_tees) } , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn profiler_wrapping_all_operators () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let runtime_context = flow . runtime_context () ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (& built . ir ()) ; let counters = RuntimeData :: new ("Fake") ; let counter_queue = RuntimeData :: new ("Fake") ; let pushed_down = built . with_default_optimize () . optimize_with (| ir | super :: profiling (ir , runtime_context , counters , counter_queue)) ; insta :: assert_debug_snapshot ! (& pushed_down . ir ()) ; let _ = pushed_down . compile_no_network :: < MultiGraph > () ; } } } pub mod properties { pub use std :: collections :: HashSet ; pub use stageleft :: * ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , SeenTees } ; pub use crate :: properties :: PropertyDatabase ; # [doc = " Allows us to convert the hydroflow datatype for folds to a binary operation for the algebra"] # [doc = " property tests."] # [allow (dead_code)] pub fn convert_hf_to_binary < I , A : Default , F : Fn (& mut A , I) > (f : F) -> impl Fn (I , I) -> A { move | a , b | { let mut acc = Default :: default () ; f (& mut acc , a) ; f (& mut acc , b) ; acc } } # [cfg (stageleft_macro)] impl PropertyDatabase { # [doc = " Tags the expression as commutative."] pub fn add_commutative_tag < 'a , I , A , F : Fn (& mut A , I) , Q : Quoted < 'a , F > + Clone > (& mut self , expr : Q ,) -> Q { let expr_clone = expr . clone () ; self . commutative . insert (expr_clone . splice ()) ; expr } pub fn is_tagged_commutative (& self , expr : & syn :: Expr) -> bool { self . commutative . contains (expr) } } pub fn properties_optimize_node < 'a > (node : & mut HfPlusNode < 'a > , db : & PropertyDatabase , seen_tees : & mut SeenTees < 'a > ,) { node . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , seen_tees ,) ; match node { HfPlusNode :: ReduceKeyed { f , .. } if db . is_tagged_commutative (& f . 0) => { dbg ! ("IDENTIFIED COMMUTATIVE OPTIMIZATION for {:?}" , & f) ; } _ => { } } } pub fn properties_optimize < 'a > (ir : Vec < HfPlusLeaf < 'a > > , db : & PropertyDatabase ,) -> Vec < HfPlusLeaf < 'a > > { let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use super :: * ; use crate :: deploy :: SingleProcessGraph ; use crate :: FlowBuilder ; # [test] fn test_property_database () { let mut db = PropertyDatabase :: default () ; assert ! (! db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; let _ = db . add_commutative_tag (q ! (| a : & mut i32 , b : i32 | * a += b)) ; assert ! (db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; } # [test] fn test_property_optimized () { let flow = FlowBuilder :: new () ; let mut database = PropertyDatabase :: default () ; let process = flow . process :: < () > () ; let counter_func = q ! (| count : & mut i32 , _ | * count += 1) ; let _ = database . add_commutative_tag (counter_func) ; flow . source_iter (& process , q ! (vec ! [])) . map (q ! (| string : String | (string , ()))) . tick_batch () . fold_keyed (q ! (|| 0) , counter_func) . all_ticks () . for_each (q ! (| (string , count) | println ! ("{}: {}" , string , count))) ; let built = flow . finalize () . optimize_with (| ir | properties_optimize (ir , & database)) . with_default_optimize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let _ = built . compile_no_network :: < SingleProcessGraph > () ; } } } pub use crate :: RuntimeContext ; # [cfg (stageleft_macro)] impl Copy for RuntimeContext < '_ > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Context > for RuntimeContext < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (quote ! (& context))) } } pub use crate :: HfCompiled ; # [cfg (stageleft_macro)] impl < 'a , ID > HfCompiled < 'a , ID > { pub fn hydroflow_ir (& self) -> & BTreeMap < usize , HydroflowGraph > { & self . hydroflow_ir } } # [cfg (stageleft_macro)] impl < 'a > HfCompiled < 'a , usize > { pub fn with_dynamic_id (self , id : impl Quoted < 'a , usize >) -> HfBuiltWithId < 'a > { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; let mut conditioned_tokens = None ; for (subgraph_id , flat_graph) in self . hydroflow_ir { let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; let my_extra_stmts = self . extra_stmts . get (& subgraph_id) . cloned () . unwrap_or_default () ; if let Some (conditioned_tokens) = conditioned_tokens . as_mut () { * conditioned_tokens = syn :: parse_quote ! { # conditioned_tokens else if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } } ; } else { conditioned_tokens = Some (syn :: parse_quote ! { if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } }) ; } } let conditioned_tokens : TokenStream = conditioned_tokens . unwrap () ; let id = id . splice () ; HfBuiltWithId { tokens : syn :: parse_quote ! ({ let __given_id = # id ; # conditioned_tokens else { panic ! ("Invalid node id: {}" , __given_id) ; } }) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfCompiled < 'a , () > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfCompiled < 'a , () > { fn to_tokens (mut self) -> (Option < TokenStream > , Option < TokenStream >) { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; if self . hydroflow_ir . len () != 1 { panic ! ("Expected exactly one subgraph in the Hydroflow IR") ; } let flat_graph = self . hydroflow_ir . remove (& 0) . unwrap () ; let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; (None , Some (tokens)) } } pub use crate :: HfBuiltWithId ; # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfBuiltWithId < 'a > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfBuiltWithId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (self . tokens)) } }
[INFO] [stdout] 1 + pub use std :: collections :: BTreeMap ; pub use std :: marker :: PhantomData ; pub use hydroflow :: scheduled :: context :: Context ; pub use hydroflow :: scheduled :: graph :: Hydroflow ; pub use hydroflow :: * ; pub use lang :: graph :: { partition_graph , HydroflowGraph } ; pub use proc_macro2 :: TokenStream ; pub use quote :: quote ; pub use stageleft :: runtime_support :: FreeVariable ; pub use stageleft :: Quoted ; pub mod runtime_support { pub use bincode ; } pub mod stream { pub use std :: cell :: RefCell ; pub use std :: hash :: Hash ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow :: bytes :: Bytes ; pub use hydroflow :: futures :: Sink ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: quote ; pub use serde :: de :: DeserializeOwned ; pub use serde :: Serialize ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use syn :: parse_quote ; pub use crate :: builder :: { ClusterIds , FlowLeaves } ; pub use crate :: cycle :: { CycleCollection , CycleComplete } ; pub use crate :: ir :: { DebugInstantiate , HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { CanSend , Location , LocationId } ; pub use crate :: { Cluster , Optional , Singleton } ; pub use crate :: stream :: Unbounded ; pub use crate :: stream :: Bounded ; pub use crate :: stream :: NoTick ; pub use crate :: stream :: Tick ; pub use crate :: stream :: Stream ; # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Stream { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Stream < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Stream { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , C , N > > ,) -> Stream < 'a , (T , O) , W , C , N > where O : Clone , { let other : Optional < 'a , O , Bounded , C , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn cross_product < O > (self , other : Stream < 'a , O , W , C , N >) -> Stream < 'a , (T , O) , W , C , N > where T : Clone , O : Clone , { if self . location_kind != other . location_kind { panic ! ("cross_product must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossProduct (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn union (self , other : Stream < 'a , T , W , C , N >) -> Stream < 'a , T , W , C , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn dest_sink < S : Unpin + Sink < T > + 'a > (self , sink : impl Quoted < 'a , S >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: DestSink { sink : sink . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn first (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } # [doc = " Allow this stream through if the other stream has elements, otherwise the output is empty."] pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } # [doc = " Allow this stream through if the other stream is empty, otherwise the output is empty."] pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn enumerate (self) -> Stream < 'a , (usize , T) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Enumerate (Box :: new (self . ir_node . into_inner ())) ,) } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn sort (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Ord , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Sort (Box :: new (self . ir_node . into_inner ())) ,) } pub fn count (self) -> Singleton < 'a , usize , Bounded , Tick , N > { self . fold (q ! (|| 0usize) , q ! (| count , _ | * count += 1)) } pub fn delta (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } pub fn unique (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Eq + Hash , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unique (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn tick_batch (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_prefix (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { self . tick_batch () . persist () } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn for_each < F : Fn (T) + 'a > (self , f : impl IntoQuotedMut < 'a , F >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: ForEach { input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , f : f . splice () . into () , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Unbounded , NoTick , N > { pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . tick_batch () . continue_if (samples . first ()) . all_ticks () } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Unbounded , NoTick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , C , N : Location > Stream < 'a , T , Bounded , C , N > { pub fn filter_not_in (self , other : Stream < 'a , T , Bounded , C , N >) -> Stream < 'a , T , Bounded , C , N > where T : Eq + Hash , { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Difference (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Stream < 'a , & T , W , C , N > { pub fn cloned (self) -> Stream < 'a , T , W , C , N > { self . map (q ! (| d | d . clone ())) } } # [cfg (stageleft_macro)] impl < 'a , K , V1 , W , C , N : Location > Stream < 'a , (K , V1) , W , C , N > { pub fn join < W2 , V2 > (self , n : Stream < 'a , (K , V2) , W2 , C , N > ,) -> Stream < 'a , (K , (V1 , V2)) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Join (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } pub fn anti_join < W2 > (self , n : Stream < 'a , K , W2 , C , N >) -> Stream < 'a , (K , V1) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("anti_join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: AntiJoin (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , K : Eq + Hash , V , N : Location > Stream < 'a , (K , V) , Bounded , Tick , N > { pub fn fold_keyed < A , I : Fn () -> A + 'a , F : Fn (& mut A , V) + 'a > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , A) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FoldKeyed { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce_keyed < F : Fn (& mut V , V) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , V) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: ReduceKeyed { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } pub fn get_this_crate () -> TokenStream { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , Span :: call_site ()) ; quote ! { # ident } } } } pub fn serialize_bincode < T : Serialize > (is_demux : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if is_demux { parse_quote ! { map (| (id , data) | { (id , # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into ()) }) } } else { parse_quote ! { map (| data | { # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into () }) } } } pub fn deserialize_bincode < T : DeserializeOwned > (tagged : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if tagged { parse_quote ! { map (| res | { let (id , b) = res . unwrap () ; (id , # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& b) . unwrap ()) }) } } else { parse_quote ! { map (| res | { # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& res . unwrap ()) . unwrap () }) } } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn send_bincode < N2 : Location , CoreType > (self , other : & N2 ,) -> Stream < 'a , N :: Out < CoreType > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T > , CoreType : Serialize + DeserializeOwned , { let serialize_pipeline = Some (serialize_bincode :: < CoreType > (N :: is_demux ())) ; let deserialize_pipeline = Some (deserialize_bincode :: < CoreType > (N :: is_tagged ())) ; Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bytes < N2 : Location > (self , other : & N2 ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T > , { Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline : None , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline : if N :: is_tagged () { Some (parse_quote ! (map (| (id , b) | (id , b . unwrap () . freeze ())))) } else { Some (parse_quote ! (map (| b | b . unwrap () . freeze ()))) } , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bincode_interleaved < N2 : Location , Tag , CoreType > (self , other : & N2 ,) -> Stream < 'a , CoreType , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T , Out < CoreType > = (Tag , CoreType) > , CoreType : Serialize + DeserializeOwned , { self . send_bincode :: < N2 , CoreType > (other) . map (q ! (| (_ , b) | b)) } pub fn send_bytes_interleaved < N2 : Location , Tag > (self , other : & N2 ,) -> Stream < 'a , Bytes , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T , Out < Bytes > = (Tag , Bytes) > , { self . send_bytes :: < N2 > (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bincode < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < T > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) > , T : Clone + Serialize + DeserializeOwned , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bincode (other) } pub fn broadcast_bincode_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , T , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) , Out < T > = (Tag , T) > + 'a , T : Clone + Serialize + DeserializeOwned , { self . broadcast_bincode (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bytes < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) > + 'a , T : Clone , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bytes (other) } pub fn broadcast_bytes_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , Bytes , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) , Out < Bytes > = (Tag , Bytes) > + 'a , T : Clone , { self . broadcast_bytes (other) . map (q ! (| (_ , b) | b)) } } } pub use stream :: { Bounded , NoTick , Stream , Tick , Unbounded } ; pub mod singleton { pub use std :: cell :: RefCell ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use crate :: builder :: FlowLeaves ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial , CycleComplete } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: Stream ; pub use crate :: singleton :: CrossResult ; # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Singleton < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Singleton :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } pub use crate :: singleton :: Singleton ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Singleton { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleComplete < 'a > for Singleton < 'a , T , Bounded , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleCollectionWithInitial < 'a > for Singleton < 'a , T , Bounded , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , initial : Self , l : LocationId ,) -> Self { Singleton :: new (l , ir_leaves , HfPlusNode :: Union (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , }) , initial . ir_node . into_inner () . into () ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Singleton < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Singleton { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , U , W , C , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (Self :: other_ir_node (other)) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Singleton < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CrossSingleton (Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , Box :: new (HfPlusNode :: Unpersist (Box :: new (Self :: other_ir_node (other)))) ,))) ,) } } pub use crate :: singleton :: Optional ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Optional { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } pub fn some (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: new (singleton . location_kind , singleton . ir_leaves , singleton . ir_node . into_inner () ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > From < Singleton < 'a , T , W , C , N > > for Optional < 'a , T , W , C , N > { fn from (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: some (singleton) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Optional < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Optional { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn into_stream (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , Tick , N > > ,) -> Optional < 'a , (T , O) , Bounded , Tick , N > where O : Clone , { let other : Optional < 'a , O , Bounded , Tick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn union (self , other : Optional < 'a , T , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Optional < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_samples (self) -> Stream < 'a , T , Unbounded , NoTick , N > { self . latest_tick () . all_ticks () } pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . latest_tick () . continue_if (samples . first ()) . latest () . tick_samples () } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Unbounded , NoTick , N > > ,) -> Optional < 'a , (T , O) , Unbounded , NoTick , N > where O : Clone , { let other : Optional < 'a , O , Unbounded , NoTick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } self . latest_tick () . cross_singleton (other . latest_tick ()) . latest () } } } pub use singleton :: { Optional , Singleton } ; pub mod location { pub use std :: marker :: PhantomData ; pub use crate :: location :: LocationId ; pub use crate :: location :: Location ; pub use crate :: location :: Process ; # [cfg (stageleft_macro)] impl < P > Clone for Process < P > { fn clone (& self) -> Self { Process { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < P > Location for Process < P > { fn id (& self) -> LocationId { LocationId :: Process (self . id) } } pub use crate :: location :: Cluster ; # [cfg (stageleft_macro)] impl < C > Clone for Cluster < C > { fn clone (& self) -> Self { Cluster { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < C > Location for Cluster < C > { fn id (& self) -> LocationId { LocationId :: Cluster (self . id) } } pub use crate :: location :: CanSend ; # [cfg (stageleft_macro)] impl < P1 , P2 > CanSend < Process < P2 > > for Process < P1 > { type In < T > = T ; type Out < T > = T ; fn is_demux () -> bool { false } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < P1 , C2 > CanSend < Cluster < C2 > > for Process < P1 > { type In < T > = (u32 , T) ; type Out < T > = T ; fn is_demux () -> bool { true } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < C1 , P2 > CanSend < Process < P2 > > for Cluster < C1 > { type In < T > = T ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { false } fn is_tagged () -> bool { true } } # [cfg (stageleft_macro)] impl < C1 , C2 > CanSend < Cluster < C2 > > for Cluster < C1 > { type In < T > = (u32 , T) ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { true } fn is_tagged () -> bool { true } } } pub use location :: { Cluster , Process } ; pub mod deploy { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use stageleft :: Quoted ; pub mod graphs { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use super :: { LocalDeploy , Node , ProcessSpec } ; pub use crate :: deploy :: graphs :: SingleProcessGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for SingleProcessGraph { type Process = SingleNode ; type Cluster = SingleNode ; type Meta = () ; type GraphId = () ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { SingleNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { SingleNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , SingleProcessGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> SingleNode { SingleNode { } } } pub use crate :: deploy :: graphs :: SingleNode ; # [cfg (stageleft_macro)] impl Node for SingleNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } pub use crate :: deploy :: graphs :: MultiGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for MultiGraph { type Process = MultiNode ; type Cluster = MultiNode ; type Meta = () ; type GraphId = usize ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { MultiNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { MultiNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , MultiGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> MultiNode { MultiNode { } } } pub use crate :: deploy :: graphs :: MultiNode ; # [cfg (stageleft_macro)] impl Node for MultiNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } } pub use graphs :: * ; pub use crate :: deploy :: LocalDeploy ; pub use crate :: deploy :: Deploy ; # [cfg (stageleft_macro)] impl < 'a , T : Deploy < 'a , Process = N , Cluster = C , Meta = M , GraphId = R > , N : Node < Meta = M > , C : Node < Meta = M > , M : Default , R , > LocalDeploy < 'a > for T { type Process = N ; type Cluster = C ; type Meta = M ; type GraphId = R ; fn has_trivial_node () -> bool { < T as Deploy < 'a > > :: has_trivial_node () } fn trivial_process (id : usize) -> Self :: Process { < T as Deploy < 'a > > :: trivial_process (id) } fn trivial_cluster (id : usize) -> Self :: Cluster { < T as Deploy < 'a > > :: trivail_cluster (id) } } pub use crate :: deploy :: ProcessSpec ; pub use crate :: deploy :: ClusterSpec ; pub use crate :: deploy :: Node ; } pub use deploy :: { ClusterSpec , Deploy , ProcessSpec } ; pub mod cycle { pub use std :: marker :: PhantomData ; pub use crate :: builder :: FlowLeaves ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: cycle :: CycleComplete ; pub use crate :: cycle :: CycleCollection ; pub use crate :: cycle :: CycleCollectionWithInitial ; pub use crate :: cycle :: HfCycle ; # [cfg (stageleft_macro)] impl < 'a , S : CycleComplete < 'a > > HfCycle < 'a , S > { pub fn complete (self , stream : S) { let ident = self . ident ; S :: complete (stream , ident) } } } pub use cycle :: HfCycle ; pub mod builder { pub use std :: cell :: RefCell ; pub use std :: collections :: HashMap ; pub use std :: marker :: PhantomData ; pub use std :: rc :: Rc ; pub use std :: time :: Duration ; pub use hydroflow :: futures :: stream :: Stream as FuturesStream ; pub use hydroflow :: { tokio , tokio_stream } ; pub use internal :: TokenStream ; pub use proc_macro2 :: Span ; pub use quote :: quote ; pub use runtime_support :: FreeVariable ; pub use stageleft :: * ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Cluster , Location , LocationId , Process } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: { HfCycle , Optional , RuntimeContext , Singleton , Stream } ; pub mod built { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use hydroflow_lang :: graph :: { eliminate_extra_unions_tees , HydroflowGraph } ; pub use super :: deploy :: { DeployFlow , DeployResult } ; pub use crate :: deploy :: { ClusterSpec , Deploy , LocalDeploy , ProcessSpec } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Cluster , Process } ; pub use crate :: HfCompiled ; pub use crate :: builder :: built :: BuiltFlow ; # [cfg (stageleft_macro)] impl < 'a > Drop for BuiltFlow < 'a > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped BuiltFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn ir (& self) -> & Vec < HfPlusLeaf < 'a > > { & self . ir } pub fn optimize_with (mut self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> BuiltFlow < 'a > { self . used = true ; BuiltFlow { ir : f (std :: mem :: take (& mut self . ir)) , processes : std :: mem :: take (& mut self . processes) , clusters : std :: mem :: take (& mut self . clusters) , used : false , _phantom : PhantomData , } } } pub fn build_inner (ir : & mut Vec < HfPlusLeaf >) -> BTreeMap < usize , HydroflowGraph > { let mut builders = BTreeMap :: new () ; let mut built_tees = HashMap :: new () ; let mut next_stmt_id = 0 ; for leaf in ir { leaf . emit (& mut builders , & mut built_tees , & mut next_stmt_id) ; } builders . into_iter () . map (| (k , v) | { let (mut flat_graph , _ , _) = v . build () ; eliminate_extra_unions_tees (& mut flat_graph) ; (k , flat_graph) }) . collect () } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn compile_no_network < D : LocalDeploy < 'a > > (mut self) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; HfCompiled { hydroflow_ir : build_inner (& mut self . ir) , extra_stmts : BTreeMap :: new () , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> BuiltFlow < 'a > { self . optimize_with (crate :: persist_pullup :: persist_pullup) } fn into_deploy < D : LocalDeploy < 'a > > (mut self) -> DeployFlow < 'a , D > { self . used = true ; let processes = if D :: has_trivial_node () { self . processes . iter () . map (| id | (* id , D :: trivial_process (* id))) . collect () } else { HashMap :: new () } ; let clusters = if D :: has_trivial_node () { self . clusters . iter () . map (| id | (* id , D :: trivial_cluster (* id))) . collect () } else { HashMap :: new () } ; DeployFlow { ir : std :: mem :: take (& mut self . ir) , nodes : processes , clusters , used : false , _phantom : PhantomData , } } pub fn with_process < P , D : LocalDeploy < 'a > > (self , process : & Process < P > , spec : impl ProcessSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_process (process , spec) } pub fn with_cluster < C , D : LocalDeploy < 'a > > (self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_cluster (cluster , spec) } pub fn compile < D : Deploy < 'a > + 'a > (self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . into_deploy :: < D > () . compile (env) } pub fn deploy < D : Deploy < 'a , CompileEnv = () > + 'a > (self , env : & mut D :: InstantiateEnv ,) -> DeployResult < 'a , D > { self . into_deploy :: < D > () . deploy (env) } } } pub mod deploy { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use proc_macro2 :: Span ; pub use stageleft :: Quoted ; pub use super :: built :: build_inner ; pub use crate :: deploy :: { LocalDeploy , Node } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: { Cluster , ClusterSpec , Deploy , HfCompiled , Process , ProcessSpec } ; pub use crate :: builder :: deploy :: DeployFlow ; # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > Drop for DeployFlow < 'a , D > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped DeployFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > DeployFlow < 'a , D > { pub fn with_process < P > (mut self , process : & Process < P > , spec : impl ProcessSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < P > () . to_string () ; self . nodes . insert (process . id , spec . build (process . id , & tag_name)) ; self } pub fn with_cluster < C > (mut self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < C > () . to_string () ; self . clusters . insert (cluster . id , spec . build (cluster . id , & tag_name)) ; self } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployFlow < 'a , D > { pub fn compile (mut self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; let mut seen_tees : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | leaf . compile_network :: < D > (env , & mut seen_tees , & self . nodes , & self . clusters)) . collect () ; let extra_stmts = self . extra_stmts (env) ; HfCompiled { hydroflow_ir : build_inner (& mut ir_leaves_networked) , extra_stmts , _phantom : PhantomData , } } fn extra_stmts (& self , env : & < D as Deploy < 'a > > :: CompileEnv) -> BTreeMap < usize , Vec < syn :: Stmt > > { let all_locations_count = self . nodes . len () + self . clusters . len () ; let mut extra_stmts : BTreeMap < usize , Vec < syn :: Stmt > > = BTreeMap :: new () ; for & c_id in self . clusters . keys () { let self_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , c_id) , Span :: call_site () ,) ; let self_id_expr = D :: cluster_self_id (env) . splice () ; extra_stmts . entry (c_id) . or_default () . push (syn :: parse_quote ! { let # self_id_ident = # self_id_expr ; }) ; for other_location in 0 .. all_locations_count { let other_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , c_id) , Span :: call_site () ,) ; let other_id_expr = D :: cluster_ids (env , c_id) . splice () ; extra_stmts . entry (other_location) . or_default () . push (syn :: parse_quote ! { let # other_id_ident = # other_id_expr ; }) ; } } extra_stmts } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a , CompileEnv = () > > DeployFlow < 'a , D > { # [must_use] pub fn deploy (mut self , env : & mut D :: InstantiateEnv) -> DeployResult < 'a , D > { self . used = true ; let mut seen_tees_instantiate : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | { leaf . compile_network :: < D > (& () , & mut seen_tees_instantiate , & self . nodes , & self . clusters ,) }) . collect () ; let mut compiled = build_inner (& mut ir_leaves_networked) ; let mut extra_stmts = self . extra_stmts (& ()) ; let mut meta = D :: Meta :: default () ; let (mut processes , mut clusters) = (std :: mem :: take (& mut self . nodes) . into_iter () . map (| (node_id , node) | { node . instantiate (env , & mut meta , compiled . remove (& node_id) . unwrap () , extra_stmts . remove (& node_id) . unwrap_or_default () ,) ; (node_id , node) }) . collect :: < HashMap < _ , _ > > () , std :: mem :: take (& mut self . clusters) . into_iter () . map (| (cluster_id , cluster) | { cluster . instantiate (env , & mut meta , compiled . remove (& cluster_id) . unwrap () , extra_stmts . remove (& cluster_id) . unwrap_or_default () ,) ; (cluster_id , cluster) }) . collect :: < HashMap < _ , _ > > () ,) ; for node in processes . values_mut () { node . update_meta (& meta) ; } for cluster in clusters . values_mut () { cluster . update_meta (& meta) ; } let mut seen_tees_connect = HashMap :: new () ; for leaf in ir_leaves_networked { leaf . connect_network (& mut seen_tees_connect) ; } DeployResult { processes , clusters , } } } pub use crate :: builder :: deploy :: DeployResult ; # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployResult < 'a , D > { pub fn get_process < P > (& self , p : & Process < P >) -> & D :: Process { let id = match p . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . processes . get (& id) . unwrap () } pub fn get_cluster < C > (& self , c : & Cluster < C >) -> & D :: Cluster { let id = match c . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . clusters . get (& id) . unwrap () } } } # [doc = " Tracks the leaves of the dataflow IR. This is referenced by"] # [doc = " `Stream` and `HfCycle` to build the IR. The inner option will"] # [doc = " be set to `None` when this builder is finalized."] pub type FlowLeaves < 'a > = Rc < RefCell < Option < Vec < HfPlusLeaf < 'a > > > > > ; pub use crate :: builder :: ClusterIds ; # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Vec < u32 > > for ClusterIds < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , & 'a Vec < u32 > > for ClusterIds < 'a > { } # [derive (Copy , Clone)] pub struct ClusterSelfId < 'a > { pub id : usize , pub _phantom : PhantomData < & 'a mut & 'a u32 > , } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < u32 > for ClusterSelfId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , u32 > for ClusterSelfId < 'a > { } pub use crate :: builder :: FlowBuilder ; # [cfg (stageleft_macro)] impl < 'a > Drop for FlowBuilder < 'a > { fn drop (& mut self) { if ! self . finalized { panic ! ("Dropped FlowBuilder without finalizing, you may have forgotten to call `with_default_optimize`, `optimize_with`, or `finalize`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > QuotedContext for FlowBuilder < 'a > { fn create () -> Self { FlowBuilder :: new () } } # [cfg (stageleft_macro)] impl < 'a > FlowBuilder < 'a > { # [allow (clippy :: new_without_default)] pub fn new () -> FlowBuilder < 'a > { FlowBuilder { ir_leaves : Rc :: new (RefCell :: new (Some (Vec :: new ()))) , nodes : RefCell :: new (vec ! []) , clusters : RefCell :: new (vec ! []) , cycle_ids : RefCell :: new (HashMap :: new ()) , next_node_id : RefCell :: new (0) , finalized : false , _phantom : PhantomData , } } pub fn finalize (mut self) -> built :: BuiltFlow < 'a > { self . finalized = true ; built :: BuiltFlow { ir : self . ir_leaves . borrow_mut () . take () . unwrap () , processes : self . nodes . replace (vec ! []) , clusters : self . clusters . replace (vec ! []) , used : false , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> built :: BuiltFlow < 'a > { self . finalize () . with_default_optimize () } pub fn optimize_with (self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> built :: BuiltFlow < 'a > { self . finalize () . optimize_with (f) } pub fn ir_leaves (& self) -> & FlowLeaves < 'a > { & self . ir_leaves } pub fn process < P > (& self) -> Process < P > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . nodes . borrow_mut () . push (id) ; Process { id , _phantom : PhantomData , } } pub fn cluster < C > (& self) -> Cluster < C > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . clusters . borrow_mut () . push (id) ; Cluster { id , _phantom : PhantomData , } } pub fn runtime_context (& self) -> RuntimeContext < 'a > { RuntimeContext { _phantom : PhantomData , } } pub fn cluster_members < C > (& self , cluster : & Cluster < C > ,) -> impl Quoted < 'a , & 'a Vec < u32 > > + Copy + 'a { ClusterIds { id : cluster . id , _phantom : PhantomData , } } pub fn cluster_self_id < C > (& self , cluster : & Cluster < C >) -> impl Quoted < 'a , u32 > + Copy + 'a { ClusterSelfId { id : cluster . id , _phantom : PhantomData , } } pub fn spin < L : Location > (& self , on : & L) -> Stream < 'a , () , Unbounded , NoTick , L > { Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Spin () , location_kind : on . id () , })) ,) } pub fn spin_batch < L : Location > (& self , on : & L , batch_size : impl Quoted < 'a , usize > + Copy + 'a ,) -> Stream < 'a , () , Bounded , Tick , L > { self . spin (on) . flat_map (q ! (move | _ | 0 .. batch_size)) . map (q ! (| _ | ())) . tick_batch () } pub fn source_stream < T , E : FuturesStream < Item = T > + Unpin , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Unbounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Stream (e . into ()) , location_kind : on . id () , })) ,) } pub fn source_iter < T , E : IntoIterator < Item = T > , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Bounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , })) ,) } pub fn singleton < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Singleton < 'a , T , Bounded , NoTick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Singleton :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,)))) ,) } pub fn singleton_first_tick < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Optional < 'a , T , Bounded , Tick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,) } pub fn source_interval < L : Location > (& self , on : & L , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , () , Unbounded , NoTick , L > { let interval = interval . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : on . id () , })) ,) } pub fn source_interval_delayed < L : Location > (& self , on : & L , delay : impl Quoted < 'a , Duration > + Copy + 'a , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , tokio :: time :: Instant , Unbounded , NoTick , L > { self . source_stream (on , q ! (tokio_stream :: wrappers :: IntervalStream :: new (tokio :: time :: interval_at (tokio :: time :: Instant :: now () + delay , interval))) ,) . tick_batch () . first () . latest () } pub fn cycle < S : CycleCollection < 'a > > (& self , on : & S :: Location) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , on . id ()) ,) } pub fn cycle_with_initial < S : CycleCollectionWithInitial < 'a > > (& self , on : & S :: Location , initial : S ,) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , initial , on . id ()) ,) } } } pub use builder :: FlowBuilder ; pub mod ir { pub use core :: panic ; pub use std :: cell :: RefCell ; pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow_lang :: graph :: FlatGraphBuilder ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: ToTokens ; pub use syn :: parse_quote ; pub use crate :: deploy :: Deploy ; pub use crate :: location :: LocationId ; pub use crate :: ir :: DebugExpr ; # [cfg (stageleft_macro)] impl From < syn :: Expr > for DebugExpr { fn from (expr : syn :: Expr) -> DebugExpr { DebugExpr (expr) } } # [cfg (stageleft_macro)] impl Deref for DebugExpr { type Target = syn :: Expr ; fn deref (& self) -> & Self :: Target { & self . 0 } } # [cfg (stageleft_macro)] impl ToTokens for DebugExpr { fn to_tokens (& self , tokens : & mut TokenStream) { self . 0 . to_tokens (tokens) ; } } # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugExpr { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "{}" , self . 0 . to_token_stream ()) } } pub use crate :: ir :: DebugInstantiate ; # [cfg (stageleft_macro)] impl < 'a > std :: fmt :: Debug for DebugInstantiate < 'a > { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<network instantiate>") } } pub use crate :: ir :: DebugPipelineFn ; # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugPipelineFn { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<function>") } } pub use crate :: ir :: HfPlusSource ; pub use crate :: ir :: HfPlusLeaf ; # [cfg (stageleft_macro)] impl < 'a > HfPlusLeaf < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . compile_network :: < D > (compile_env , s , nodes , clusters) ; } , seen_tees ,) } pub fn connect_network (self , seen_tees : & mut SeenTees < 'a >) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . connect_network (s) ; } , seen_tees ,) } pub fn transform_children (self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) -> HfPlusLeaf < 'a > { match self { HfPlusLeaf :: ForEach { f , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: ForEach { f , input } } HfPlusLeaf :: DestSink { sink , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: DestSink { sink , input } } HfPlusLeaf :: CycleSink { ident , location_kind , mut input , } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: CycleSink { ident , location_kind , input , } } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) { match self { HfPlusLeaf :: ForEach { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> for_each (# f) ; }) ; } HfPlusLeaf :: DestSink { sink , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink) ; }) ; } HfPlusLeaf :: CycleSink { ident , location_kind , input , } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; assert_eq ! (input_location_id , * location_id , "cycle_sink location mismatch") ; graph_builders . entry (* location_id) . or_default () . add_statement (parse_quote ! { # ident = # input_ident ; }) ; } } } } pub use crate :: ir :: HfPlusNode ; pub type SeenTees < 'a > = HashMap < * const RefCell < HfPlusNode < 'a > > , Rc < RefCell < HfPlusNode < 'a > > > > ; # [cfg (stageleft_macro)] impl < 'a > HfPlusNode < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (& mut self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) { self . transform_children (| n , s | n . compile_network :: < D > (compile_env , s , nodes , clusters) , seen_tees ,) ; if let HfPlusNode :: Network { from_location , to_location , instantiate_fn , .. } = self { let (sink_expr , source_expr , connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { let ((sink , source) , connect_fn) = match (from_location , to_location) { (LocationId :: Process (from) , LocationId :: Process (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: o2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Process (from) , LocationId :: Cluster (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: o2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Process (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: m2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Cluster (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: m2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } } ; (sink , source , connect_fn) } DebugInstantiate :: Finalized (_ , _ , _) => panic ! ("network already finalized") , } ; * instantiate_fn = DebugInstantiate :: Finalized (sink_expr , source_expr , connect_fn) ; } } pub fn connect_network (& mut self , seen_tees : & mut SeenTees < 'a >) { self . transform_children (| n , s | n . connect_network (s) , seen_tees) ; if let HfPlusNode :: Network { instantiate_fn , .. } = self { match instantiate_fn { DebugInstantiate :: Building () => panic ! ("network not built") , DebugInstantiate :: Finalized (_ , _ , ref connect_fn) => { connect_fn () ; } } } } pub fn transform_children (& mut self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) { match self { HfPlusNode :: Placeholder => { panic ! () ; } HfPlusNode :: Source { .. } => { } HfPlusNode :: CycleSource { .. } => { } HfPlusNode :: Tee { inner } => { if let Some (transformed) = seen_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { * inner = transformed . clone () ; } else { let transformed_cell = Rc :: new (RefCell :: new (HfPlusNode :: Placeholder)) ; seen_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , transformed_cell . clone () ,) ; let mut orig = inner . replace (HfPlusNode :: Placeholder) ; transform (& mut orig , seen_tees) ; * transformed_cell . borrow_mut () = orig ; * inner = transformed_cell ; } } HfPlusNode :: Persist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Unpersist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Delta (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Union (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossProduct (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossSingleton (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Join (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Difference (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: AntiJoin (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Map { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FlatMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Filter { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FilterMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Sort (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: DeferTick (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Enumerate (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Inspect { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Unique (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Fold { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FoldKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Reduce { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: ReduceKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Network { input , .. } => { transform (input . as_mut () , seen_tees) ; } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) -> (syn :: Ident , usize) { match self { HfPlusNode :: Placeholder => { panic ! () } HfPlusNode :: Persist (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let persist_id = * next_stmt_id ; * next_stmt_id += 1 ; let persist_ident = syn :: Ident :: new (& format ! ("stream_{}" , persist_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # persist_ident = # inner_ident -> persist ::<'static > () ; }) ; (persist_ident , location) } HfPlusNode :: Unpersist (_) => { panic ! ("Unpersist is a marker node and should have been optimized away. This is likely a compiler bug.") } HfPlusNode :: Delta (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let delta_id = * next_stmt_id ; * next_stmt_id += 1 ; let delta_ident = syn :: Ident :: new (& format ! ("stream_{}" , delta_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # delta_ident = # inner_ident -> multiset_delta () ; }) ; (delta_ident , location) } HfPlusNode :: Source { source , location_kind , } => { let source_id = * next_stmt_id ; * next_stmt_id += 1 ; let source_ident = syn :: Ident :: new (& format ! ("stream_{}" , source_id) , Span :: call_site ()) ; let source_stmt = match source { HfPlusSource :: Stream (expr) => { parse_quote ! { # source_ident = source_stream (# expr) ; } } HfPlusSource :: Iter (expr) => { parse_quote ! { # source_ident = source_iter (# expr) ; } } HfPlusSource :: Interval (expr) => { parse_quote ! { # source_ident = source_interval (# expr) ; } } HfPlusSource :: Spin () => { parse_quote ! { # source_ident = spin () ; } } } ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; graph_builders . entry (* location_id) . or_default () . add_statement (source_stmt) ; (source_ident , * location_id) } HfPlusNode :: CycleSource { ident , location_kind , } => { let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; (ident . clone () , * location_id) } HfPlusNode :: Tee { inner } => { if let Some (ret) = built_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { ret . clone () } else { let (inner_ident , inner_location_id) = inner . borrow () . emit (graph_builders , built_tees , next_stmt_id) ; let tee_id = * next_stmt_id ; * next_stmt_id += 1 ; let tee_ident = syn :: Ident :: new (& format ! ("stream_{}" , tee_id) , Span :: call_site ()) ; let builder = graph_builders . entry (inner_location_id) . or_default () ; builder . add_statement (parse_quote ! { # tee_ident = # inner_ident -> tee () ; }) ; built_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , (tee_ident . clone () , inner_location_id) ,) ; (tee_ident , inner_location_id) } } HfPlusNode :: Union (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "union inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let union_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # union_ident = union () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [0] # union_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # union_ident ; }) ; (union_ident , left_location_id) } HfPlusNode :: CrossSingleton (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "cross_singleton inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let cross_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # cross_ident = cross_singleton () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [input] # cross_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [single] # cross_ident ; }) ; (cross_ident , left_location_id) } HfPlusNode :: CrossProduct (..) | HfPlusNode :: Join (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: CrossProduct (..)) { parse_quote ! (cross_join_multiset) } else { parse_quote ! (join_multiset) } ; let (HfPlusNode :: CrossProduct (left , right) | HfPlusNode :: Join (left , right)) = self else { unreachable ! () } ; let (left_inner , left_was_persist) = if let HfPlusNode :: Persist (left) = left . as_ref () { (left , true) } else { (left , false) } ; let (right_inner , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left_inner . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right_inner . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "join / cross product inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; match (left_was_persist , right_was_persist) { (true , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'static > () ; }) ; } (true , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'tick > () ; }) ; } (false , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } (false , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } } ; builder . add_statement (parse_quote ! { # left_ident -> [0] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Difference (..) | HfPlusNode :: AntiJoin (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Difference (..)) { parse_quote ! (difference_multiset) } else { parse_quote ! (anti_join_multiset) } ; let (HfPlusNode :: Difference (left , right) | HfPlusNode :: AntiJoin (left , right)) = self else { unreachable ! () } ; let (right , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "difference / anti join inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; if right_was_persist { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } else { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } builder . add_statement (parse_quote ! { # left_ident -> [pos] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [neg] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Map { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let map_id = * next_stmt_id ; * next_stmt_id += 1 ; let map_ident = syn :: Ident :: new (& format ! ("stream_{}" , map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # map_ident = # input_ident -> map (# f) ; }) ; (map_ident , input_location_id) } HfPlusNode :: FlatMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let flat_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let flat_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , flat_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # flat_map_ident = # input_ident -> flat_map (# f) ; }) ; (flat_map_ident , input_location_id) } HfPlusNode :: Filter { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_ident = # input_ident -> filter (# f) ; }) ; (filter_ident , input_location_id) } HfPlusNode :: FilterMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_map_ident = # input_ident -> filter_map (# f) ; }) ; (filter_map_ident , input_location_id) } HfPlusNode :: Sort (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sort_id = * next_stmt_id ; * next_stmt_id += 1 ; let sort_ident = syn :: Ident :: new (& format ! ("stream_{}" , sort_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # sort_ident = # input_ident -> sort () ; }) ; (sort_ident , input_location_id) } HfPlusNode :: DeferTick (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let defer_tick_id = * next_stmt_id ; * next_stmt_id += 1 ; let defer_tick_ident = syn :: Ident :: new (& format ! ("stream_{}" , defer_tick_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # defer_tick_ident = # input_ident -> defer_tick_lazy () ; }) ; (defer_tick_ident , input_location_id) } HfPlusNode :: Enumerate (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let enumerate_id = * next_stmt_id ; * next_stmt_id += 1 ; let enumerate_ident = syn :: Ident :: new (& format ! ("stream_{}" , enumerate_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # enumerate_ident = # input_ident -> enumerate () ; }) ; (enumerate_ident , input_location_id) } HfPlusNode :: Inspect { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let inspect_id = * next_stmt_id ; * next_stmt_id += 1 ; let inspect_ident = syn :: Ident :: new (& format ! ("stream_{}" , inspect_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # inspect_ident = # input_ident -> inspect (# f) ; }) ; (inspect_ident , input_location_id) } HfPlusNode :: Unique (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let unique_id = * next_stmt_id ; * next_stmt_id += 1 ; let unique_ident = syn :: Ident :: new (& format ! ("stream_{}" , unique_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # unique_ident = # input_ident -> unique ::<'tick > () ; }) ; (unique_ident , input_location_id) } HfPlusNode :: Fold { .. } | HfPlusNode :: FoldKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Fold { .. }) { parse_quote ! (fold) } else { parse_quote ! (fold_keyed) } ; let (HfPlusNode :: Fold { init , acc , input } | HfPlusNode :: FoldKeyed { init , acc , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let fold_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'static > (# init , # acc) ; }) ; } else { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'tick > (# init , # acc) ; }) ; } (fold_ident , input_location_id) } HfPlusNode :: Reduce { .. } | HfPlusNode :: ReduceKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Reduce { .. }) { parse_quote ! (reduce) } else { parse_quote ! (reduce_keyed) } ; let (HfPlusNode :: Reduce { f , input } | HfPlusNode :: ReduceKeyed { f , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let reduce_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'static > (# f) ; }) ; } else { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'tick > (# f) ; }) ; } (reduce_ident , input_location_id) } HfPlusNode :: Network { from_location : _ , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input , } => { let (sink_expr , source_expr , _connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { panic ! ("Expected the network to be finalized") } DebugInstantiate :: Finalized (sink , source , connect_fn) => { (sink , source , connect_fn) } } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sender_builder = graph_builders . entry (input_location_id) . or_default () ; if let Some (serialize_pipeline) = serialize_pipeline { sender_builder . add_statement (parse_quote ! { # input_ident -> # serialize_pipeline -> dest_sink (# sink_expr) ; }) ; } else { sender_builder . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink_expr) ; }) ; } let to_id = match to_location { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let receiver_builder = graph_builders . entry (* to_id) . or_default () ; let receiver_stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let receiver_stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , receiver_stream_id) , Span :: call_site ()) ; if let Some (deserialize_pipeline) = deserialize_pipeline { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) -> # deserialize_pipeline ; }) ; } else { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) ; }) ; } (receiver_stream_ident , * to_id) } } } } } pub mod persist_pullup { pub use std :: cell :: RefCell ; pub use std :: collections :: HashSet ; pub use std :: ops :: Deref ; pub use crate :: ir :: * ; pub fn persist_pullup_node < 'a > (node : & mut HfPlusNode < 'a > , seen_tees : & mut SeenTees < 'a > , persist_pulled_tees : & mut HashSet < * const RefCell < HfPlusNode < 'a > > > ,) { node . transform_children (| n , s | persist_pullup_node (n , s , persist_pulled_tees) , seen_tees ,) ; match node { HfPlusNode :: Unpersist (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Unpersist (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Delta (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Delta (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Tee { inner } => { if persist_pulled_tees . contains (& (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >)) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } else { let inner_borrow = inner . borrow () ; if let HfPlusNode :: Persist (_) = inner_borrow . deref () { drop (inner_borrow) ; persist_pulled_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >) ; if let HfPlusNode :: Persist (box behind_persist) = inner . replace (HfPlusNode :: Placeholder) { * inner . borrow_mut () = behind_persist ; } else { unreachable ! () } * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } } } HfPlusNode :: Map { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Map { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Map { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: FlatMap { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: FlatMap { f , input : HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: FlatMap { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Filter { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Filter { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Filter { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Network { input : box HfPlusNode :: Persist (_) , .. } => { if let HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Union (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Union (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Union (left , right))) ; } else { unreachable ! () } } HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: CrossProduct (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,) ,)))) ; } else { unreachable ! () } } HfPlusNode :: Join (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Join (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: Join (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,))))) ; } else { unreachable ! () } } _ => { } } } pub fn persist_pullup (ir : Vec < HfPlusLeaf >) -> Vec < HfPlusLeaf > { let mut seen_tees = Default :: default () ; let mut persist_pulled_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| n , s | persist_pullup_node (n , s , & mut persist_pulled_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn persist_pullup_through_map () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } # [test] fn persist_pullup_behind_tee () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; let before_tee = flow . source_iter (& process , q ! (0 .. 10)) . tick_batch () . persist () ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } } } pub mod profiler { pub use std :: cell :: RefCell ; pub use hydroflow :: futures :: channel :: mpsc :: UnboundedSender ; pub use stageleft :: * ; pub use crate as hydroflow_plus ; pub use crate :: ir :: * ; pub use crate :: RuntimeContext ; pub fn increment_counter (count : & mut u64) { * count += 1 ; } pub fn quoted_any_fn < 'a , F : Fn (& usize) + 'a , Q : IntoQuotedMut < 'a , F > > (q : Q) -> Q { q } # [doc = " Add a profiling node before each node to count the cardinality of its input"] pub fn add_profiling_node < 'a > (node : & mut HfPlusNode < 'a > , _context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > , id : & mut u32 , seen_tees : & mut SeenTees < 'a > ,) { let my_id = * id ; * id += 1 ; node . transform_children (| node , seen_tees | { add_profiling_node (node , _context , counters , counter_queue , id , seen_tees) } , seen_tees ,) ; let orig_node = std :: mem :: replace (node , HfPlusNode :: Placeholder) ; * node = HfPlusNode :: Inspect { f : quoted_any_fn (q ! ({ counter_queue . borrow () . unbounded_send ((my_id as usize , counters . borrow () [my_id as usize])) . unwrap () ; counters . borrow_mut () [my_id as usize] = 0 ; move | _ | { hydroflow_plus :: profiler :: increment_counter (& mut counters . borrow_mut () [my_id as usize] ,) ; } })) . splice () . into () , input : Box :: new (orig_node) , } } # [doc = " Count the cardinality of each input and periodically output to a file"] pub fn profiling < 'a > (ir : Vec < HfPlusLeaf < 'a > > , context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > ,) -> Vec < HfPlusLeaf < 'a > > { let mut id = 0 ; let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | { add_profiling_node (node , context , counters , counter_queue , & mut id , seen_tees) } , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn profiler_wrapping_all_operators () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let runtime_context = flow . runtime_context () ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (& built . ir ()) ; let counters = RuntimeData :: new ("Fake") ; let counter_queue = RuntimeData :: new ("Fake") ; let pushed_down = built . with_default_optimize () . optimize_with (| ir | super :: profiling (ir , runtime_context , counters , counter_queue)) ; insta :: assert_debug_snapshot ! (& pushed_down . ir ()) ; let _ = pushed_down . compile_no_network :: < MultiGraph > () ; } } } pub mod properties { pub use std :: collections :: HashSet ; pub use stageleft :: * ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , SeenTees } ; pub use crate :: properties :: PropertyDatabase ; # [doc = " Allows us to convert the hydroflow datatype for folds to a binary operation for the algebra"] # [doc = " property tests."] # [allow (dead_code)] pub fn convert_hf_to_binary < I , A : Default , F : Fn (& mut A , I) > (f : F) -> impl Fn (I , I) -> A { move | a , b | { let mut acc = Default :: default () ; f (& mut acc , a) ; f (& mut acc , b) ; acc } } # [cfg (stageleft_macro)] impl PropertyDatabase { # [doc = " Tags the expression as commutative."] pub fn add_commutative_tag < 'a , I , A , F : Fn (& mut A , I) , Q : Quoted < 'a , F > + Clone > (& mut self , expr : Q ,) -> Q { let expr_clone = expr . clone () ; self . commutative . insert (expr_clone . splice ()) ; expr } pub fn is_tagged_commutative (& self , expr : & syn :: Expr) -> bool { self . commutative . contains (expr) } } pub fn properties_optimize_node < 'a > (node : & mut HfPlusNode < 'a > , db : & PropertyDatabase , seen_tees : & mut SeenTees < 'a > ,) { node . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , seen_tees ,) ; match node { HfPlusNode :: ReduceKeyed { f , .. } if db . is_tagged_commutative (& f . 0) => { dbg ! ("IDENTIFIED COMMUTATIVE OPTIMIZATION for {:?}" , & f) ; } _ => { } } } pub fn properties_optimize < 'a > (ir : Vec < HfPlusLeaf < 'a > > , db : & PropertyDatabase ,) -> Vec < HfPlusLeaf < 'a > > { let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use super :: * ; use crate :: deploy :: SingleProcessGraph ; use crate :: FlowBuilder ; # [test] fn test_property_database () { let mut db = PropertyDatabase :: default () ; assert ! (! db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; let _ = db . add_commutative_tag (q ! (| a : & mut i32 , b : i32 | * a += b)) ; assert ! (db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; } # [test] fn test_property_optimized () { let flow = FlowBuilder :: new () ; let mut database = PropertyDatabase :: default () ; let process = flow . process :: < () > () ; let counter_func = q ! (| count : & mut i32 , _ | * count += 1) ; let _ = database . add_commutative_tag (counter_func) ; flow . source_iter (& process , q ! (vec ! [])) . map (q ! (| string : String | (string , ()))) . tick_batch () . fold_keyed (q ! (|| 0) , counter_func) . all_ticks () . for_each (q ! (| (string , count) | println ! ("{}: {}" , string , count))) ; let built = flow . finalize () . optimize_with (| ir | properties_optimize (ir , & database)) . with_default_optimize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let _ = built . compile_no_network :: < SingleProcessGraph > () ; } } } pub use crate :: RuntimeContext ; # [cfg (stageleft_macro)] impl Copy for RuntimeContext < '_ > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Context > for RuntimeContext < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (quote ! (& context))) } } pub use crate :: HfCompiled ; # [cfg (stageleft_macro)] impl < 'a , ID > HfCompiled < 'a , ID > { pub fn hydroflow_ir (& self) -> & BTreeMap < usize , HydroflowGraph > { & self . hydroflow_ir } } # [cfg (stageleft_macro)] impl < 'a > HfCompiled < 'a , usize > { pub fn with_dynamic_id (self , id : impl Quoted < 'a , usize >) -> HfBuiltWithId < 'a > { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; let mut conditioned_tokens = None ; for (subgraph_id , flat_graph) in self . hydroflow_ir { let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; let my_extra_stmts = self . extra_stmts . get (& subgraph_id) . cloned () . unwrap_or_default () ; if let Some (conditioned_tokens) = conditioned_tokens . as_mut () { * conditioned_tokens = syn :: parse_quote ! { # conditioned_tokens else if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } } ; } else { conditioned_tokens = Some (syn :: parse_quote ! { if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } }) ; } } let conditioned_tokens : TokenStream = conditioned_tokens . unwrap () ; let id = id . splice () ; HfBuiltWithId { tokens : syn :: parse_quote ! ({ let __given_id = # id ; # conditioned_tokens else { panic ! ("Invalid node id: {}" , __given_id) ; } }) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfCompiled < 'a , () > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfCompiled < 'a , () > { fn to_tokens (mut self) -> (Option < TokenStream > , Option < TokenStream >) { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; if self . hydroflow_ir . len () != 1 { panic ! ("Expected exactly one subgraph in the Hydroflow IR") ; } let flat_graph = self . hydroflow_ir . remove (& 0) . unwrap () ; let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; (None , Some (tokens)) } } pub use crate :: HfBuiltWithId ; # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfBuiltWithId < 'a > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfBuiltWithId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (self . tokens)) } }
[INFO] [stdout]   |
[INFO] [stdout] help: ...otherwise replace it with an invocation of macro `deref`
[INFO] [stdout]   |
[INFO] [stdout] 1 - pub use std :: collections :: BTreeMap ; pub use std :: marker :: PhantomData ; pub use hydroflow :: scheduled :: context :: Context ; pub use hydroflow :: scheduled :: graph :: Hydroflow ; pub use hydroflow :: * ; pub use lang :: graph :: { partition_graph , HydroflowGraph } ; pub use proc_macro2 :: TokenStream ; pub use quote :: quote ; pub use stageleft :: runtime_support :: FreeVariable ; pub use stageleft :: Quoted ; pub mod runtime_support { pub use bincode ; } pub mod stream { pub use std :: cell :: RefCell ; pub use std :: hash :: Hash ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow :: bytes :: Bytes ; pub use hydroflow :: futures :: Sink ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: quote ; pub use serde :: de :: DeserializeOwned ; pub use serde :: Serialize ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use syn :: parse_quote ; pub use crate :: builder :: { ClusterIds , FlowLeaves } ; pub use crate :: cycle :: { CycleCollection , CycleComplete } ; pub use crate :: ir :: { DebugInstantiate , HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { CanSend , Location , LocationId } ; pub use crate :: { Cluster , Optional , Singleton } ; pub use crate :: stream :: Unbounded ; pub use crate :: stream :: Bounded ; pub use crate :: stream :: NoTick ; pub use crate :: stream :: Tick ; pub use crate :: stream :: Stream ; # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Stream { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Stream < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Stream { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , C , N > > ,) -> Stream < 'a , (T , O) , W , C , N > where O : Clone , { let other : Optional < 'a , O , Bounded , C , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn cross_product < O > (self , other : Stream < 'a , O , W , C , N >) -> Stream < 'a , (T , O) , W , C , N > where T : Clone , O : Clone , { if self . location_kind != other . location_kind { panic ! ("cross_product must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossProduct (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn union (self , other : Stream < 'a , T , W , C , N >) -> Stream < 'a , T , W , C , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn dest_sink < S : Unpin + Sink < T > + 'a > (self , sink : impl Quoted < 'a , S >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: DestSink { sink : sink . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn first (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } # [doc = " Allow this stream through if the other stream has elements, otherwise the output is empty."] pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } # [doc = " Allow this stream through if the other stream is empty, otherwise the output is empty."] pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn enumerate (self) -> Stream < 'a , (usize , T) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Enumerate (Box :: new (self . ir_node . into_inner ())) ,) } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn sort (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Ord , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Sort (Box :: new (self . ir_node . into_inner ())) ,) } pub fn count (self) -> Singleton < 'a , usize , Bounded , Tick , N > { self . fold (q ! (|| 0usize) , q ! (| count , _ | * count += 1)) } pub fn delta (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } pub fn unique (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Eq + Hash , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unique (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn tick_batch (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_prefix (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { self . tick_batch () . persist () } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn for_each < F : Fn (T) + 'a > (self , f : impl IntoQuotedMut < 'a , F >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: ForEach { input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , f : f . splice () . into () , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Unbounded , NoTick , N > { pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . tick_batch () . continue_if (samples . first ()) . all_ticks () } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Unbounded , NoTick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , C , N : Location > Stream < 'a , T , Bounded , C , N > { pub fn filter_not_in (self , other : Stream < 'a , T , Bounded , C , N >) -> Stream < 'a , T , Bounded , C , N > where T : Eq + Hash , { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Difference (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Stream < 'a , & T , W , C , N > { pub fn cloned (self) -> Stream < 'a , T , W , C , N > { self . map (q ! (| d | d . clone ())) } } # [cfg (stageleft_macro)] impl < 'a , K , V1 , W , C , N : Location > Stream < 'a , (K , V1) , W , C , N > { pub fn join < W2 , V2 > (self , n : Stream < 'a , (K , V2) , W2 , C , N > ,) -> Stream < 'a , (K , (V1 , V2)) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Join (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } pub fn anti_join < W2 > (self , n : Stream < 'a , K , W2 , C , N >) -> Stream < 'a , (K , V1) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("anti_join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: AntiJoin (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , K : Eq + Hash , V , N : Location > Stream < 'a , (K , V) , Bounded , Tick , N > { pub fn fold_keyed < A , I : Fn () -> A + 'a , F : Fn (& mut A , V) + 'a > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , A) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FoldKeyed { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce_keyed < F : Fn (& mut V , V) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , V) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: ReduceKeyed { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } pub fn get_this_crate () -> TokenStream { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , Span :: call_site ()) ; quote ! { # ident } } } } pub fn serialize_bincode < T : Serialize > (is_demux : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if is_demux { parse_quote ! { map (| (id , data) | { (id , # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into ()) }) } } else { parse_quote ! { map (| data | { # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into () }) } } } pub fn deserialize_bincode < T : DeserializeOwned > (tagged : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if tagged { parse_quote ! { map (| res | { let (id , b) = res . unwrap () ; (id , # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& b) . unwrap ()) }) } } else { parse_quote ! { map (| res | { # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& res . unwrap ()) . unwrap () }) } } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn send_bincode < N2 : Location , CoreType > (self , other : & N2 ,) -> Stream < 'a , N :: Out < CoreType > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T > , CoreType : Serialize + DeserializeOwned , { let serialize_pipeline = Some (serialize_bincode :: < CoreType > (N :: is_demux ())) ; let deserialize_pipeline = Some (deserialize_bincode :: < CoreType > (N :: is_tagged ())) ; Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bytes < N2 : Location > (self , other : & N2 ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T > , { Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline : None , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline : if N :: is_tagged () { Some (parse_quote ! (map (| (id , b) | (id , b . unwrap () . freeze ())))) } else { Some (parse_quote ! (map (| b | b . unwrap () . freeze ()))) } , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bincode_interleaved < N2 : Location , Tag , CoreType > (self , other : & N2 ,) -> Stream < 'a , CoreType , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T , Out < CoreType > = (Tag , CoreType) > , CoreType : Serialize + DeserializeOwned , { self . send_bincode :: < N2 , CoreType > (other) . map (q ! (| (_ , b) | b)) } pub fn send_bytes_interleaved < N2 : Location , Tag > (self , other : & N2 ,) -> Stream < 'a , Bytes , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T , Out < Bytes > = (Tag , Bytes) > , { self . send_bytes :: < N2 > (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bincode < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < T > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) > , T : Clone + Serialize + DeserializeOwned , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bincode (other) } pub fn broadcast_bincode_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , T , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) , Out < T > = (Tag , T) > + 'a , T : Clone + Serialize + DeserializeOwned , { self . broadcast_bincode (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bytes < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) > + 'a , T : Clone , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bytes (other) } pub fn broadcast_bytes_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , Bytes , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) , Out < Bytes > = (Tag , Bytes) > + 'a , T : Clone , { self . broadcast_bytes (other) . map (q ! (| (_ , b) | b)) } } } pub use stream :: { Bounded , NoTick , Stream , Tick , Unbounded } ; pub mod singleton { pub use std :: cell :: RefCell ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use crate :: builder :: FlowLeaves ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial , CycleComplete } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: Stream ; pub use crate :: singleton :: CrossResult ; # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Singleton < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Singleton :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } pub use crate :: singleton :: Singleton ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Singleton { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleComplete < 'a > for Singleton < 'a , T , Bounded , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleCollectionWithInitial < 'a > for Singleton < 'a , T , Bounded , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , initial : Self , l : LocationId ,) -> Self { Singleton :: new (l , ir_leaves , HfPlusNode :: Union (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , }) , initial . ir_node . into_inner () . into () ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Singleton < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Singleton { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , U , W , C , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (Self :: other_ir_node (other)) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Singleton < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CrossSingleton (Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , Box :: new (HfPlusNode :: Unpersist (Box :: new (Self :: other_ir_node (other)))) ,))) ,) } } pub use crate :: singleton :: Optional ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Optional { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } pub fn some (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: new (singleton . location_kind , singleton . ir_leaves , singleton . ir_node . into_inner () ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > From < Singleton < 'a , T , W , C , N > > for Optional < 'a , T , W , C , N > { fn from (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: some (singleton) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Optional < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Optional { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn into_stream (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , Tick , N > > ,) -> Optional < 'a , (T , O) , Bounded , Tick , N > where O : Clone , { let other : Optional < 'a , O , Bounded , Tick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn union (self , other : Optional < 'a , T , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Optional < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_samples (self) -> Stream < 'a , T , Unbounded , NoTick , N > { self . latest_tick () . all_ticks () } pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . latest_tick () . continue_if (samples . first ()) . latest () . tick_samples () } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Unbounded , NoTick , N > > ,) -> Optional < 'a , (T , O) , Unbounded , NoTick , N > where O : Clone , { let other : Optional < 'a , O , Unbounded , NoTick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } self . latest_tick () . cross_singleton (other . latest_tick ()) . latest () } } } pub use singleton :: { Optional , Singleton } ; pub mod location { pub use std :: marker :: PhantomData ; pub use crate :: location :: LocationId ; pub use crate :: location :: Location ; pub use crate :: location :: Process ; # [cfg (stageleft_macro)] impl < P > Clone for Process < P > { fn clone (& self) -> Self { Process { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < P > Location for Process < P > { fn id (& self) -> LocationId { LocationId :: Process (self . id) } } pub use crate :: location :: Cluster ; # [cfg (stageleft_macro)] impl < C > Clone for Cluster < C > { fn clone (& self) -> Self { Cluster { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < C > Location for Cluster < C > { fn id (& self) -> LocationId { LocationId :: Cluster (self . id) } } pub use crate :: location :: CanSend ; # [cfg (stageleft_macro)] impl < P1 , P2 > CanSend < Process < P2 > > for Process < P1 > { type In < T > = T ; type Out < T > = T ; fn is_demux () -> bool { false } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < P1 , C2 > CanSend < Cluster < C2 > > for Process < P1 > { type In < T > = (u32 , T) ; type Out < T > = T ; fn is_demux () -> bool { true } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < C1 , P2 > CanSend < Process < P2 > > for Cluster < C1 > { type In < T > = T ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { false } fn is_tagged () -> bool { true } } # [cfg (stageleft_macro)] impl < C1 , C2 > CanSend < Cluster < C2 > > for Cluster < C1 > { type In < T > = (u32 , T) ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { true } fn is_tagged () -> bool { true } } } pub use location :: { Cluster , Process } ; pub mod deploy { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use stageleft :: Quoted ; pub mod graphs { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use super :: { LocalDeploy , Node , ProcessSpec } ; pub use crate :: deploy :: graphs :: SingleProcessGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for SingleProcessGraph { type Process = SingleNode ; type Cluster = SingleNode ; type Meta = () ; type GraphId = () ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { SingleNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { SingleNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , SingleProcessGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> SingleNode { SingleNode { } } } pub use crate :: deploy :: graphs :: SingleNode ; # [cfg (stageleft_macro)] impl Node for SingleNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } pub use crate :: deploy :: graphs :: MultiGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for MultiGraph { type Process = MultiNode ; type Cluster = MultiNode ; type Meta = () ; type GraphId = usize ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { MultiNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { MultiNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , MultiGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> MultiNode { MultiNode { } } } pub use crate :: deploy :: graphs :: MultiNode ; # [cfg (stageleft_macro)] impl Node for MultiNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } } pub use graphs :: * ; pub use crate :: deploy :: LocalDeploy ; pub use crate :: deploy :: Deploy ; # [cfg (stageleft_macro)] impl < 'a , T : Deploy < 'a , Process = N , Cluster = C , Meta = M , GraphId = R > , N : Node < Meta = M > , C : Node < Meta = M > , M : Default , R , > LocalDeploy < 'a > for T { type Process = N ; type Cluster = C ; type Meta = M ; type GraphId = R ; fn has_trivial_node () -> bool { < T as Deploy < 'a > > :: has_trivial_node () } fn trivial_process (id : usize) -> Self :: Process { < T as Deploy < 'a > > :: trivial_process (id) } fn trivial_cluster (id : usize) -> Self :: Cluster { < T as Deploy < 'a > > :: trivail_cluster (id) } } pub use crate :: deploy :: ProcessSpec ; pub use crate :: deploy :: ClusterSpec ; pub use crate :: deploy :: Node ; } pub use deploy :: { ClusterSpec , Deploy , ProcessSpec } ; pub mod cycle { pub use std :: marker :: PhantomData ; pub use crate :: builder :: FlowLeaves ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: cycle :: CycleComplete ; pub use crate :: cycle :: CycleCollection ; pub use crate :: cycle :: CycleCollectionWithInitial ; pub use crate :: cycle :: HfCycle ; # [cfg (stageleft_macro)] impl < 'a , S : CycleComplete < 'a > > HfCycle < 'a , S > { pub fn complete (self , stream : S) { let ident = self . ident ; S :: complete (stream , ident) } } } pub use cycle :: HfCycle ; pub mod builder { pub use std :: cell :: RefCell ; pub use std :: collections :: HashMap ; pub use std :: marker :: PhantomData ; pub use std :: rc :: Rc ; pub use std :: time :: Duration ; pub use hydroflow :: futures :: stream :: Stream as FuturesStream ; pub use hydroflow :: { tokio , tokio_stream } ; pub use internal :: TokenStream ; pub use proc_macro2 :: Span ; pub use quote :: quote ; pub use runtime_support :: FreeVariable ; pub use stageleft :: * ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Cluster , Location , LocationId , Process } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: { HfCycle , Optional , RuntimeContext , Singleton , Stream } ; pub mod built { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use hydroflow_lang :: graph :: { eliminate_extra_unions_tees , HydroflowGraph } ; pub use super :: deploy :: { DeployFlow , DeployResult } ; pub use crate :: deploy :: { ClusterSpec , Deploy , LocalDeploy , ProcessSpec } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Cluster , Process } ; pub use crate :: HfCompiled ; pub use crate :: builder :: built :: BuiltFlow ; # [cfg (stageleft_macro)] impl < 'a > Drop for BuiltFlow < 'a > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped BuiltFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn ir (& self) -> & Vec < HfPlusLeaf < 'a > > { & self . ir } pub fn optimize_with (mut self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> BuiltFlow < 'a > { self . used = true ; BuiltFlow { ir : f (std :: mem :: take (& mut self . ir)) , processes : std :: mem :: take (& mut self . processes) , clusters : std :: mem :: take (& mut self . clusters) , used : false , _phantom : PhantomData , } } } pub fn build_inner (ir : & mut Vec < HfPlusLeaf >) -> BTreeMap < usize , HydroflowGraph > { let mut builders = BTreeMap :: new () ; let mut built_tees = HashMap :: new () ; let mut next_stmt_id = 0 ; for leaf in ir { leaf . emit (& mut builders , & mut built_tees , & mut next_stmt_id) ; } builders . into_iter () . map (| (k , v) | { let (mut flat_graph , _ , _) = v . build () ; eliminate_extra_unions_tees (& mut flat_graph) ; (k , flat_graph) }) . collect () } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn compile_no_network < D : LocalDeploy < 'a > > (mut self) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; HfCompiled { hydroflow_ir : build_inner (& mut self . ir) , extra_stmts : BTreeMap :: new () , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> BuiltFlow < 'a > { self . optimize_with (crate :: persist_pullup :: persist_pullup) } fn into_deploy < D : LocalDeploy < 'a > > (mut self) -> DeployFlow < 'a , D > { self . used = true ; let processes = if D :: has_trivial_node () { self . processes . iter () . map (| id | (* id , D :: trivial_process (* id))) . collect () } else { HashMap :: new () } ; let clusters = if D :: has_trivial_node () { self . clusters . iter () . map (| id | (* id , D :: trivial_cluster (* id))) . collect () } else { HashMap :: new () } ; DeployFlow { ir : std :: mem :: take (& mut self . ir) , nodes : processes , clusters , used : false , _phantom : PhantomData , } } pub fn with_process < P , D : LocalDeploy < 'a > > (self , process : & Process < P > , spec : impl ProcessSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_process (process , spec) } pub fn with_cluster < C , D : LocalDeploy < 'a > > (self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_cluster (cluster , spec) } pub fn compile < D : Deploy < 'a > + 'a > (self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . into_deploy :: < D > () . compile (env) } pub fn deploy < D : Deploy < 'a , CompileEnv = () > + 'a > (self , env : & mut D :: InstantiateEnv ,) -> DeployResult < 'a , D > { self . into_deploy :: < D > () . deploy (env) } } } pub mod deploy { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use proc_macro2 :: Span ; pub use stageleft :: Quoted ; pub use super :: built :: build_inner ; pub use crate :: deploy :: { LocalDeploy , Node } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: { Cluster , ClusterSpec , Deploy , HfCompiled , Process , ProcessSpec } ; pub use crate :: builder :: deploy :: DeployFlow ; # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > Drop for DeployFlow < 'a , D > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped DeployFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > DeployFlow < 'a , D > { pub fn with_process < P > (mut self , process : & Process < P > , spec : impl ProcessSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < P > () . to_string () ; self . nodes . insert (process . id , spec . build (process . id , & tag_name)) ; self } pub fn with_cluster < C > (mut self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < C > () . to_string () ; self . clusters . insert (cluster . id , spec . build (cluster . id , & tag_name)) ; self } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployFlow < 'a , D > { pub fn compile (mut self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; let mut seen_tees : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | leaf . compile_network :: < D > (env , & mut seen_tees , & self . nodes , & self . clusters)) . collect () ; let extra_stmts = self . extra_stmts (env) ; HfCompiled { hydroflow_ir : build_inner (& mut ir_leaves_networked) , extra_stmts , _phantom : PhantomData , } } fn extra_stmts (& self , env : & < D as Deploy < 'a > > :: CompileEnv) -> BTreeMap < usize , Vec < syn :: Stmt > > { let all_locations_count = self . nodes . len () + self . clusters . len () ; let mut extra_stmts : BTreeMap < usize , Vec < syn :: Stmt > > = BTreeMap :: new () ; for & c_id in self . clusters . keys () { let self_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , c_id) , Span :: call_site () ,) ; let self_id_expr = D :: cluster_self_id (env) . splice () ; extra_stmts . entry (c_id) . or_default () . push (syn :: parse_quote ! { let # self_id_ident = # self_id_expr ; }) ; for other_location in 0 .. all_locations_count { let other_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , c_id) , Span :: call_site () ,) ; let other_id_expr = D :: cluster_ids (env , c_id) . splice () ; extra_stmts . entry (other_location) . or_default () . push (syn :: parse_quote ! { let # other_id_ident = # other_id_expr ; }) ; } } extra_stmts } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a , CompileEnv = () > > DeployFlow < 'a , D > { # [must_use] pub fn deploy (mut self , env : & mut D :: InstantiateEnv) -> DeployResult < 'a , D > { self . used = true ; let mut seen_tees_instantiate : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | { leaf . compile_network :: < D > (& () , & mut seen_tees_instantiate , & self . nodes , & self . clusters ,) }) . collect () ; let mut compiled = build_inner (& mut ir_leaves_networked) ; let mut extra_stmts = self . extra_stmts (& ()) ; let mut meta = D :: Meta :: default () ; let (mut processes , mut clusters) = (std :: mem :: take (& mut self . nodes) . into_iter () . map (| (node_id , node) | { node . instantiate (env , & mut meta , compiled . remove (& node_id) . unwrap () , extra_stmts . remove (& node_id) . unwrap_or_default () ,) ; (node_id , node) }) . collect :: < HashMap < _ , _ > > () , std :: mem :: take (& mut self . clusters) . into_iter () . map (| (cluster_id , cluster) | { cluster . instantiate (env , & mut meta , compiled . remove (& cluster_id) . unwrap () , extra_stmts . remove (& cluster_id) . unwrap_or_default () ,) ; (cluster_id , cluster) }) . collect :: < HashMap < _ , _ > > () ,) ; for node in processes . values_mut () { node . update_meta (& meta) ; } for cluster in clusters . values_mut () { cluster . update_meta (& meta) ; } let mut seen_tees_connect = HashMap :: new () ; for leaf in ir_leaves_networked { leaf . connect_network (& mut seen_tees_connect) ; } DeployResult { processes , clusters , } } } pub use crate :: builder :: deploy :: DeployResult ; # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployResult < 'a , D > { pub fn get_process < P > (& self , p : & Process < P >) -> & D :: Process { let id = match p . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . processes . get (& id) . unwrap () } pub fn get_cluster < C > (& self , c : & Cluster < C >) -> & D :: Cluster { let id = match c . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . clusters . get (& id) . unwrap () } } } # [doc = " Tracks the leaves of the dataflow IR. This is referenced by"] # [doc = " `Stream` and `HfCycle` to build the IR. The inner option will"] # [doc = " be set to `None` when this builder is finalized."] pub type FlowLeaves < 'a > = Rc < RefCell < Option < Vec < HfPlusLeaf < 'a > > > > > ; pub use crate :: builder :: ClusterIds ; # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Vec < u32 > > for ClusterIds < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , & 'a Vec < u32 > > for ClusterIds < 'a > { } # [derive (Copy , Clone)] pub struct ClusterSelfId < 'a > { pub id : usize , pub _phantom : PhantomData < & 'a mut & 'a u32 > , } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < u32 > for ClusterSelfId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , u32 > for ClusterSelfId < 'a > { } pub use crate :: builder :: FlowBuilder ; # [cfg (stageleft_macro)] impl < 'a > Drop for FlowBuilder < 'a > { fn drop (& mut self) { if ! self . finalized { panic ! ("Dropped FlowBuilder without finalizing, you may have forgotten to call `with_default_optimize`, `optimize_with`, or `finalize`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > QuotedContext for FlowBuilder < 'a > { fn create () -> Self { FlowBuilder :: new () } } # [cfg (stageleft_macro)] impl < 'a > FlowBuilder < 'a > { # [allow (clippy :: new_without_default)] pub fn new () -> FlowBuilder < 'a > { FlowBuilder { ir_leaves : Rc :: new (RefCell :: new (Some (Vec :: new ()))) , nodes : RefCell :: new (vec ! []) , clusters : RefCell :: new (vec ! []) , cycle_ids : RefCell :: new (HashMap :: new ()) , next_node_id : RefCell :: new (0) , finalized : false , _phantom : PhantomData , } } pub fn finalize (mut self) -> built :: BuiltFlow < 'a > { self . finalized = true ; built :: BuiltFlow { ir : self . ir_leaves . borrow_mut () . take () . unwrap () , processes : self . nodes . replace (vec ! []) , clusters : self . clusters . replace (vec ! []) , used : false , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> built :: BuiltFlow < 'a > { self . finalize () . with_default_optimize () } pub fn optimize_with (self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> built :: BuiltFlow < 'a > { self . finalize () . optimize_with (f) } pub fn ir_leaves (& self) -> & FlowLeaves < 'a > { & self . ir_leaves } pub fn process < P > (& self) -> Process < P > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . nodes . borrow_mut () . push (id) ; Process { id , _phantom : PhantomData , } } pub fn cluster < C > (& self) -> Cluster < C > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . clusters . borrow_mut () . push (id) ; Cluster { id , _phantom : PhantomData , } } pub fn runtime_context (& self) -> RuntimeContext < 'a > { RuntimeContext { _phantom : PhantomData , } } pub fn cluster_members < C > (& self , cluster : & Cluster < C > ,) -> impl Quoted < 'a , & 'a Vec < u32 > > + Copy + 'a { ClusterIds { id : cluster . id , _phantom : PhantomData , } } pub fn cluster_self_id < C > (& self , cluster : & Cluster < C >) -> impl Quoted < 'a , u32 > + Copy + 'a { ClusterSelfId { id : cluster . id , _phantom : PhantomData , } } pub fn spin < L : Location > (& self , on : & L) -> Stream < 'a , () , Unbounded , NoTick , L > { Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Spin () , location_kind : on . id () , })) ,) } pub fn spin_batch < L : Location > (& self , on : & L , batch_size : impl Quoted < 'a , usize > + Copy + 'a ,) -> Stream < 'a , () , Bounded , Tick , L > { self . spin (on) . flat_map (q ! (move | _ | 0 .. batch_size)) . map (q ! (| _ | ())) . tick_batch () } pub fn source_stream < T , E : FuturesStream < Item = T > + Unpin , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Unbounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Stream (e . into ()) , location_kind : on . id () , })) ,) } pub fn source_iter < T , E : IntoIterator < Item = T > , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Bounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , })) ,) } pub fn singleton < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Singleton < 'a , T , Bounded , NoTick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Singleton :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,)))) ,) } pub fn singleton_first_tick < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Optional < 'a , T , Bounded , Tick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,) } pub fn source_interval < L : Location > (& self , on : & L , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , () , Unbounded , NoTick , L > { let interval = interval . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : on . id () , })) ,) } pub fn source_interval_delayed < L : Location > (& self , on : & L , delay : impl Quoted < 'a , Duration > + Copy + 'a , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , tokio :: time :: Instant , Unbounded , NoTick , L > { self . source_stream (on , q ! (tokio_stream :: wrappers :: IntervalStream :: new (tokio :: time :: interval_at (tokio :: time :: Instant :: now () + delay , interval))) ,) . tick_batch () . first () . latest () } pub fn cycle < S : CycleCollection < 'a > > (& self , on : & S :: Location) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , on . id ()) ,) } pub fn cycle_with_initial < S : CycleCollectionWithInitial < 'a > > (& self , on : & S :: Location , initial : S ,) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , initial , on . id ()) ,) } } } pub use builder :: FlowBuilder ; pub mod ir { pub use core :: panic ; pub use std :: cell :: RefCell ; pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow_lang :: graph :: FlatGraphBuilder ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: ToTokens ; pub use syn :: parse_quote ; pub use crate :: deploy :: Deploy ; pub use crate :: location :: LocationId ; pub use crate :: ir :: DebugExpr ; # [cfg (stageleft_macro)] impl From < syn :: Expr > for DebugExpr { fn from (expr : syn :: Expr) -> DebugExpr { DebugExpr (expr) } } # [cfg (stageleft_macro)] impl Deref for DebugExpr { type Target = syn :: Expr ; fn deref (& self) -> & Self :: Target { & self . 0 } } # [cfg (stageleft_macro)] impl ToTokens for DebugExpr { fn to_tokens (& self , tokens : & mut TokenStream) { self . 0 . to_tokens (tokens) ; } } # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugExpr { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "{}" , self . 0 . to_token_stream ()) } } pub use crate :: ir :: DebugInstantiate ; # [cfg (stageleft_macro)] impl < 'a > std :: fmt :: Debug for DebugInstantiate < 'a > { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<network instantiate>") } } pub use crate :: ir :: DebugPipelineFn ; # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugPipelineFn { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<function>") } } pub use crate :: ir :: HfPlusSource ; pub use crate :: ir :: HfPlusLeaf ; # [cfg (stageleft_macro)] impl < 'a > HfPlusLeaf < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . compile_network :: < D > (compile_env , s , nodes , clusters) ; } , seen_tees ,) } pub fn connect_network (self , seen_tees : & mut SeenTees < 'a >) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . connect_network (s) ; } , seen_tees ,) } pub fn transform_children (self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) -> HfPlusLeaf < 'a > { match self { HfPlusLeaf :: ForEach { f , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: ForEach { f , input } } HfPlusLeaf :: DestSink { sink , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: DestSink { sink , input } } HfPlusLeaf :: CycleSink { ident , location_kind , mut input , } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: CycleSink { ident , location_kind , input , } } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) { match self { HfPlusLeaf :: ForEach { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> for_each (# f) ; }) ; } HfPlusLeaf :: DestSink { sink , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink) ; }) ; } HfPlusLeaf :: CycleSink { ident , location_kind , input , } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; assert_eq ! (input_location_id , * location_id , "cycle_sink location mismatch") ; graph_builders . entry (* location_id) . or_default () . add_statement (parse_quote ! { # ident = # input_ident ; }) ; } } } } pub use crate :: ir :: HfPlusNode ; pub type SeenTees < 'a > = HashMap < * const RefCell < HfPlusNode < 'a > > , Rc < RefCell < HfPlusNode < 'a > > > > ; # [cfg (stageleft_macro)] impl < 'a > HfPlusNode < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (& mut self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) { self . transform_children (| n , s | n . compile_network :: < D > (compile_env , s , nodes , clusters) , seen_tees ,) ; if let HfPlusNode :: Network { from_location , to_location , instantiate_fn , .. } = self { let (sink_expr , source_expr , connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { let ((sink , source) , connect_fn) = match (from_location , to_location) { (LocationId :: Process (from) , LocationId :: Process (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: o2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Process (from) , LocationId :: Cluster (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: o2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Process (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: m2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Cluster (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: m2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } } ; (sink , source , connect_fn) } DebugInstantiate :: Finalized (_ , _ , _) => panic ! ("network already finalized") , } ; * instantiate_fn = DebugInstantiate :: Finalized (sink_expr , source_expr , connect_fn) ; } } pub fn connect_network (& mut self , seen_tees : & mut SeenTees < 'a >) { self . transform_children (| n , s | n . connect_network (s) , seen_tees) ; if let HfPlusNode :: Network { instantiate_fn , .. } = self { match instantiate_fn { DebugInstantiate :: Building () => panic ! ("network not built") , DebugInstantiate :: Finalized (_ , _ , ref connect_fn) => { connect_fn () ; } } } } pub fn transform_children (& mut self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) { match self { HfPlusNode :: Placeholder => { panic ! () ; } HfPlusNode :: Source { .. } => { } HfPlusNode :: CycleSource { .. } => { } HfPlusNode :: Tee { inner } => { if let Some (transformed) = seen_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { * inner = transformed . clone () ; } else { let transformed_cell = Rc :: new (RefCell :: new (HfPlusNode :: Placeholder)) ; seen_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , transformed_cell . clone () ,) ; let mut orig = inner . replace (HfPlusNode :: Placeholder) ; transform (& mut orig , seen_tees) ; * transformed_cell . borrow_mut () = orig ; * inner = transformed_cell ; } } HfPlusNode :: Persist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Unpersist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Delta (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Union (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossProduct (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossSingleton (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Join (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Difference (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: AntiJoin (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Map { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FlatMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Filter { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FilterMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Sort (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: DeferTick (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Enumerate (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Inspect { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Unique (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Fold { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FoldKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Reduce { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: ReduceKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Network { input , .. } => { transform (input . as_mut () , seen_tees) ; } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) -> (syn :: Ident , usize) { match self { HfPlusNode :: Placeholder => { panic ! () } HfPlusNode :: Persist (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let persist_id = * next_stmt_id ; * next_stmt_id += 1 ; let persist_ident = syn :: Ident :: new (& format ! ("stream_{}" , persist_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # persist_ident = # inner_ident -> persist ::<'static > () ; }) ; (persist_ident , location) } HfPlusNode :: Unpersist (_) => { panic ! ("Unpersist is a marker node and should have been optimized away. This is likely a compiler bug.") } HfPlusNode :: Delta (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let delta_id = * next_stmt_id ; * next_stmt_id += 1 ; let delta_ident = syn :: Ident :: new (& format ! ("stream_{}" , delta_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # delta_ident = # inner_ident -> multiset_delta () ; }) ; (delta_ident , location) } HfPlusNode :: Source { source , location_kind , } => { let source_id = * next_stmt_id ; * next_stmt_id += 1 ; let source_ident = syn :: Ident :: new (& format ! ("stream_{}" , source_id) , Span :: call_site ()) ; let source_stmt = match source { HfPlusSource :: Stream (expr) => { parse_quote ! { # source_ident = source_stream (# expr) ; } } HfPlusSource :: Iter (expr) => { parse_quote ! { # source_ident = source_iter (# expr) ; } } HfPlusSource :: Interval (expr) => { parse_quote ! { # source_ident = source_interval (# expr) ; } } HfPlusSource :: Spin () => { parse_quote ! { # source_ident = spin () ; } } } ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; graph_builders . entry (* location_id) . or_default () . add_statement (source_stmt) ; (source_ident , * location_id) } HfPlusNode :: CycleSource { ident , location_kind , } => { let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; (ident . clone () , * location_id) } HfPlusNode :: Tee { inner } => { if let Some (ret) = built_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { ret . clone () } else { let (inner_ident , inner_location_id) = inner . borrow () . emit (graph_builders , built_tees , next_stmt_id) ; let tee_id = * next_stmt_id ; * next_stmt_id += 1 ; let tee_ident = syn :: Ident :: new (& format ! ("stream_{}" , tee_id) , Span :: call_site ()) ; let builder = graph_builders . entry (inner_location_id) . or_default () ; builder . add_statement (parse_quote ! { # tee_ident = # inner_ident -> tee () ; }) ; built_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , (tee_ident . clone () , inner_location_id) ,) ; (tee_ident , inner_location_id) } } HfPlusNode :: Union (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "union inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let union_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # union_ident = union () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [0] # union_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # union_ident ; }) ; (union_ident , left_location_id) } HfPlusNode :: CrossSingleton (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "cross_singleton inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let cross_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # cross_ident = cross_singleton () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [input] # cross_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [single] # cross_ident ; }) ; (cross_ident , left_location_id) } HfPlusNode :: CrossProduct (..) | HfPlusNode :: Join (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: CrossProduct (..)) { parse_quote ! (cross_join_multiset) } else { parse_quote ! (join_multiset) } ; let (HfPlusNode :: CrossProduct (left , right) | HfPlusNode :: Join (left , right)) = self else { unreachable ! () } ; let (left_inner , left_was_persist) = if let HfPlusNode :: Persist (left) = left . as_ref () { (left , true) } else { (left , false) } ; let (right_inner , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left_inner . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right_inner . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "join / cross product inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; match (left_was_persist , right_was_persist) { (true , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'static > () ; }) ; } (true , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'tick > () ; }) ; } (false , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } (false , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } } ; builder . add_statement (parse_quote ! { # left_ident -> [0] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Difference (..) | HfPlusNode :: AntiJoin (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Difference (..)) { parse_quote ! (difference_multiset) } else { parse_quote ! (anti_join_multiset) } ; let (HfPlusNode :: Difference (left , right) | HfPlusNode :: AntiJoin (left , right)) = self else { unreachable ! () } ; let (right , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "difference / anti join inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; if right_was_persist { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } else { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } builder . add_statement (parse_quote ! { # left_ident -> [pos] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [neg] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Map { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let map_id = * next_stmt_id ; * next_stmt_id += 1 ; let map_ident = syn :: Ident :: new (& format ! ("stream_{}" , map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # map_ident = # input_ident -> map (# f) ; }) ; (map_ident , input_location_id) } HfPlusNode :: FlatMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let flat_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let flat_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , flat_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # flat_map_ident = # input_ident -> flat_map (# f) ; }) ; (flat_map_ident , input_location_id) } HfPlusNode :: Filter { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_ident = # input_ident -> filter (# f) ; }) ; (filter_ident , input_location_id) } HfPlusNode :: FilterMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_map_ident = # input_ident -> filter_map (# f) ; }) ; (filter_map_ident , input_location_id) } HfPlusNode :: Sort (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sort_id = * next_stmt_id ; * next_stmt_id += 1 ; let sort_ident = syn :: Ident :: new (& format ! ("stream_{}" , sort_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # sort_ident = # input_ident -> sort () ; }) ; (sort_ident , input_location_id) } HfPlusNode :: DeferTick (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let defer_tick_id = * next_stmt_id ; * next_stmt_id += 1 ; let defer_tick_ident = syn :: Ident :: new (& format ! ("stream_{}" , defer_tick_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # defer_tick_ident = # input_ident -> defer_tick_lazy () ; }) ; (defer_tick_ident , input_location_id) } HfPlusNode :: Enumerate (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let enumerate_id = * next_stmt_id ; * next_stmt_id += 1 ; let enumerate_ident = syn :: Ident :: new (& format ! ("stream_{}" , enumerate_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # enumerate_ident = # input_ident -> enumerate () ; }) ; (enumerate_ident , input_location_id) } HfPlusNode :: Inspect { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let inspect_id = * next_stmt_id ; * next_stmt_id += 1 ; let inspect_ident = syn :: Ident :: new (& format ! ("stream_{}" , inspect_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # inspect_ident = # input_ident -> inspect (# f) ; }) ; (inspect_ident , input_location_id) } HfPlusNode :: Unique (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let unique_id = * next_stmt_id ; * next_stmt_id += 1 ; let unique_ident = syn :: Ident :: new (& format ! ("stream_{}" , unique_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # unique_ident = # input_ident -> unique ::<'tick > () ; }) ; (unique_ident , input_location_id) } HfPlusNode :: Fold { .. } | HfPlusNode :: FoldKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Fold { .. }) { parse_quote ! (fold) } else { parse_quote ! (fold_keyed) } ; let (HfPlusNode :: Fold { init , acc , input } | HfPlusNode :: FoldKeyed { init , acc , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let fold_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'static > (# init , # acc) ; }) ; } else { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'tick > (# init , # acc) ; }) ; } (fold_ident , input_location_id) } HfPlusNode :: Reduce { .. } | HfPlusNode :: ReduceKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Reduce { .. }) { parse_quote ! (reduce) } else { parse_quote ! (reduce_keyed) } ; let (HfPlusNode :: Reduce { f , input } | HfPlusNode :: ReduceKeyed { f , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let reduce_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'static > (# f) ; }) ; } else { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'tick > (# f) ; }) ; } (reduce_ident , input_location_id) } HfPlusNode :: Network { from_location : _ , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input , } => { let (sink_expr , source_expr , _connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { panic ! ("Expected the network to be finalized") } DebugInstantiate :: Finalized (sink , source , connect_fn) => { (sink , source , connect_fn) } } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sender_builder = graph_builders . entry (input_location_id) . or_default () ; if let Some (serialize_pipeline) = serialize_pipeline { sender_builder . add_statement (parse_quote ! { # input_ident -> # serialize_pipeline -> dest_sink (# sink_expr) ; }) ; } else { sender_builder . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink_expr) ; }) ; } let to_id = match to_location { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let receiver_builder = graph_builders . entry (* to_id) . or_default () ; let receiver_stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let receiver_stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , receiver_stream_id) , Span :: call_site ()) ; if let Some (deserialize_pipeline) = deserialize_pipeline { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) -> # deserialize_pipeline ; }) ; } else { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) ; }) ; } (receiver_stream_ident , * to_id) } } } } } pub mod persist_pullup { pub use std :: cell :: RefCell ; pub use std :: collections :: HashSet ; pub use std :: ops :: Deref ; pub use crate :: ir :: * ; pub fn persist_pullup_node < 'a > (node : & mut HfPlusNode < 'a > , seen_tees : & mut SeenTees < 'a > , persist_pulled_tees : & mut HashSet < * const RefCell < HfPlusNode < 'a > > > ,) { node . transform_children (| n , s | persist_pullup_node (n , s , persist_pulled_tees) , seen_tees ,) ; match node { HfPlusNode :: Unpersist (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Unpersist (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Delta (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Delta (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Tee { inner } => { if persist_pulled_tees . contains (& (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >)) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } else { let inner_borrow = inner . borrow () ; if let HfPlusNode :: Persist (_) = inner_borrow . deref () { drop (inner_borrow) ; persist_pulled_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >) ; if let HfPlusNode :: Persist (box behind_persist) = inner . replace (HfPlusNode :: Placeholder) { * inner . borrow_mut () = behind_persist ; } else { unreachable ! () } * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } } } HfPlusNode :: Map { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Map { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Map { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: FlatMap { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: FlatMap { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: FlatMap { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Filter { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Filter { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Filter { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Network { input : box HfPlusNode :: Persist (_) , .. } => { if let HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Union (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Union (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Union (left , right))) ; } else { unreachable ! () } } HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: CrossProduct (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,) ,)))) ; } else { unreachable ! () } } HfPlusNode :: Join (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Join (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: Join (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,))))) ; } else { unreachable ! () } } _ => { } } } pub fn persist_pullup (ir : Vec < HfPlusLeaf >) -> Vec < HfPlusLeaf > { let mut seen_tees = Default :: default () ; let mut persist_pulled_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| n , s | persist_pullup_node (n , s , & mut persist_pulled_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn persist_pullup_through_map () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } # [test] fn persist_pullup_behind_tee () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; let before_tee = flow . source_iter (& process , q ! (0 .. 10)) . tick_batch () . persist () ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } } } pub mod profiler { pub use std :: cell :: RefCell ; pub use hydroflow :: futures :: channel :: mpsc :: UnboundedSender ; pub use stageleft :: * ; pub use crate as hydroflow_plus ; pub use crate :: ir :: * ; pub use crate :: RuntimeContext ; pub fn increment_counter (count : & mut u64) { * count += 1 ; } pub fn quoted_any_fn < 'a , F : Fn (& usize) + 'a , Q : IntoQuotedMut < 'a , F > > (q : Q) -> Q { q } # [doc = " Add a profiling node before each node to count the cardinality of its input"] pub fn add_profiling_node < 'a > (node : & mut HfPlusNode < 'a > , _context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > , id : & mut u32 , seen_tees : & mut SeenTees < 'a > ,) { let my_id = * id ; * id += 1 ; node . transform_children (| node , seen_tees | { add_profiling_node (node , _context , counters , counter_queue , id , seen_tees) } , seen_tees ,) ; let orig_node = std :: mem :: replace (node , HfPlusNode :: Placeholder) ; * node = HfPlusNode :: Inspect { f : quoted_any_fn (q ! ({ counter_queue . borrow () . unbounded_send ((my_id as usize , counters . borrow () [my_id as usize])) . unwrap () ; counters . borrow_mut () [my_id as usize] = 0 ; move | _ | { hydroflow_plus :: profiler :: increment_counter (& mut counters . borrow_mut () [my_id as usize] ,) ; } })) . splice () . into () , input : Box :: new (orig_node) , } } # [doc = " Count the cardinality of each input and periodically output to a file"] pub fn profiling < 'a > (ir : Vec < HfPlusLeaf < 'a > > , context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > ,) -> Vec < HfPlusLeaf < 'a > > { let mut id = 0 ; let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | { add_profiling_node (node , context , counters , counter_queue , & mut id , seen_tees) } , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn profiler_wrapping_all_operators () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let runtime_context = flow . runtime_context () ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (& built . ir ()) ; let counters = RuntimeData :: new ("Fake") ; let counter_queue = RuntimeData :: new ("Fake") ; let pushed_down = built . with_default_optimize () . optimize_with (| ir | super :: profiling (ir , runtime_context , counters , counter_queue)) ; insta :: assert_debug_snapshot ! (& pushed_down . ir ()) ; let _ = pushed_down . compile_no_network :: < MultiGraph > () ; } } } pub mod properties { pub use std :: collections :: HashSet ; pub use stageleft :: * ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , SeenTees } ; pub use crate :: properties :: PropertyDatabase ; # [doc = " Allows us to convert the hydroflow datatype for folds to a binary operation for the algebra"] # [doc = " property tests."] # [allow (dead_code)] pub fn convert_hf_to_binary < I , A : Default , F : Fn (& mut A , I) > (f : F) -> impl Fn (I , I) -> A { move | a , b | { let mut acc = Default :: default () ; f (& mut acc , a) ; f (& mut acc , b) ; acc } } # [cfg (stageleft_macro)] impl PropertyDatabase { # [doc = " Tags the expression as commutative."] pub fn add_commutative_tag < 'a , I , A , F : Fn (& mut A , I) , Q : Quoted < 'a , F > + Clone > (& mut self , expr : Q ,) -> Q { let expr_clone = expr . clone () ; self . commutative . insert (expr_clone . splice ()) ; expr } pub fn is_tagged_commutative (& self , expr : & syn :: Expr) -> bool { self . commutative . contains (expr) } } pub fn properties_optimize_node < 'a > (node : & mut HfPlusNode < 'a > , db : & PropertyDatabase , seen_tees : & mut SeenTees < 'a > ,) { node . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , seen_tees ,) ; match node { HfPlusNode :: ReduceKeyed { f , .. } if db . is_tagged_commutative (& f . 0) => { dbg ! ("IDENTIFIED COMMUTATIVE OPTIMIZATION for {:?}" , & f) ; } _ => { } } } pub fn properties_optimize < 'a > (ir : Vec < HfPlusLeaf < 'a > > , db : & PropertyDatabase ,) -> Vec < HfPlusLeaf < 'a > > { let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use super :: * ; use crate :: deploy :: SingleProcessGraph ; use crate :: FlowBuilder ; # [test] fn test_property_database () { let mut db = PropertyDatabase :: default () ; assert ! (! db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; let _ = db . add_commutative_tag (q ! (| a : & mut i32 , b : i32 | * a += b)) ; assert ! (db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; } # [test] fn test_property_optimized () { let flow = FlowBuilder :: new () ; let mut database = PropertyDatabase :: default () ; let process = flow . process :: < () > () ; let counter_func = q ! (| count : & mut i32 , _ | * count += 1) ; let _ = database . add_commutative_tag (counter_func) ; flow . source_iter (& process , q ! (vec ! [])) . map (q ! (| string : String | (string , ()))) . tick_batch () . fold_keyed (q ! (|| 0) , counter_func) . all_ticks () . for_each (q ! (| (string , count) | println ! ("{}: {}" , string , count))) ; let built = flow . finalize () . optimize_with (| ir | properties_optimize (ir , & database)) . with_default_optimize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let _ = built . compile_no_network :: < SingleProcessGraph > () ; } } } pub use crate :: RuntimeContext ; # [cfg (stageleft_macro)] impl Copy for RuntimeContext < '_ > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Context > for RuntimeContext < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (quote ! (& context))) } } pub use crate :: HfCompiled ; # [cfg (stageleft_macro)] impl < 'a , ID > HfCompiled < 'a , ID > { pub fn hydroflow_ir (& self) -> & BTreeMap < usize , HydroflowGraph > { & self . hydroflow_ir } } # [cfg (stageleft_macro)] impl < 'a > HfCompiled < 'a , usize > { pub fn with_dynamic_id (self , id : impl Quoted < 'a , usize >) -> HfBuiltWithId < 'a > { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; let mut conditioned_tokens = None ; for (subgraph_id , flat_graph) in self . hydroflow_ir { let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; let my_extra_stmts = self . extra_stmts . get (& subgraph_id) . cloned () . unwrap_or_default () ; if let Some (conditioned_tokens) = conditioned_tokens . as_mut () { * conditioned_tokens = syn :: parse_quote ! { # conditioned_tokens else if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } } ; } else { conditioned_tokens = Some (syn :: parse_quote ! { if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } }) ; } } let conditioned_tokens : TokenStream = conditioned_tokens . unwrap () ; let id = id . splice () ; HfBuiltWithId { tokens : syn :: parse_quote ! ({ let __given_id = # id ; # conditioned_tokens else { panic ! ("Invalid node id: {}" , __given_id) ; } }) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfCompiled < 'a , () > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfCompiled < 'a , () > { fn to_tokens (mut self) -> (Option < TokenStream > , Option < TokenStream >) { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; if self . hydroflow_ir . len () != 1 { panic ! ("Expected exactly one subgraph in the Hydroflow IR") ; } let flat_graph = self . hydroflow_ir . remove (& 0) . unwrap () ; let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; (None , Some (tokens)) } } pub use crate :: HfBuiltWithId ; # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfBuiltWithId < 'a > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfBuiltWithId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (self . tokens)) } }
[INFO] [stdout] 1 + pub use std :: collections :: BTreeMap ; pub use std :: marker :: PhantomData ; pub use hydroflow :: scheduled :: context :: Context ; pub use hydroflow :: scheduled :: graph :: Hydroflow ; pub use hydroflow :: * ; pub use lang :: graph :: { partition_graph , HydroflowGraph } ; pub use proc_macro2 :: TokenStream ; pub use quote :: quote ; pub use stageleft :: runtime_support :: FreeVariable ; pub use stageleft :: Quoted ; pub mod runtime_support { pub use bincode ; } pub mod stream { pub use std :: cell :: RefCell ; pub use std :: hash :: Hash ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow :: bytes :: Bytes ; pub use hydroflow :: futures :: Sink ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: quote ; pub use serde :: de :: DeserializeOwned ; pub use serde :: Serialize ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use syn :: parse_quote ; pub use crate :: builder :: { ClusterIds , FlowLeaves } ; pub use crate :: cycle :: { CycleCollection , CycleComplete } ; pub use crate :: ir :: { DebugInstantiate , HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { CanSend , Location , LocationId } ; pub use crate :: { Cluster , Optional , Singleton } ; pub use crate :: stream :: Unbounded ; pub use crate :: stream :: Bounded ; pub use crate :: stream :: NoTick ; pub use crate :: stream :: Tick ; pub use crate :: stream :: Stream ; # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Stream { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Stream < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Stream { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , C , N > > ,) -> Stream < 'a , (T , O) , W , C , N > where O : Clone , { let other : Optional < 'a , O , Bounded , C , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn cross_product < O > (self , other : Stream < 'a , O , W , C , N >) -> Stream < 'a , (T , O) , W , C , N > where T : Clone , O : Clone , { if self . location_kind != other . location_kind { panic ! ("cross_product must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossProduct (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn union (self , other : Stream < 'a , T , W , C , N >) -> Stream < 'a , T , W , C , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn dest_sink < S : Unpin + Sink < T > + 'a > (self , sink : impl Quoted < 'a , S >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: DestSink { sink : sink . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn first (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } # [doc = " Allow this stream through if the other stream has elements, otherwise the output is empty."] pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } # [doc = " Allow this stream through if the other stream is empty, otherwise the output is empty."] pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn enumerate (self) -> Stream < 'a , (usize , T) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Enumerate (Box :: new (self . ir_node . into_inner ())) ,) } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn sort (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Ord , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Sort (Box :: new (self . ir_node . into_inner ())) ,) } pub fn count (self) -> Singleton < 'a , usize , Bounded , Tick , N > { self . fold (q ! (|| 0usize) , q ! (| count , _ | * count += 1)) } pub fn delta (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } pub fn unique (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Eq + Hash , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unique (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn tick_batch (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_prefix (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { self . tick_batch () . persist () } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn for_each < F : Fn (T) + 'a > (self , f : impl IntoQuotedMut < 'a , F >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: ForEach { input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , f : f . splice () . into () , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Unbounded , NoTick , N > { pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . tick_batch () . continue_if (samples . first ()) . all_ticks () } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Unbounded , NoTick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , C , N : Location > Stream < 'a , T , Bounded , C , N > { pub fn filter_not_in (self , other : Stream < 'a , T , Bounded , C , N >) -> Stream < 'a , T , Bounded , C , N > where T : Eq + Hash , { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Difference (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Stream < 'a , & T , W , C , N > { pub fn cloned (self) -> Stream < 'a , T , W , C , N > { self . map (q ! (| d | d . clone ())) } } # [cfg (stageleft_macro)] impl < 'a , K , V1 , W , C , N : Location > Stream < 'a , (K , V1) , W , C , N > { pub fn join < W2 , V2 > (self , n : Stream < 'a , (K , V2) , W2 , C , N > ,) -> Stream < 'a , (K , (V1 , V2)) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Join (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } pub fn anti_join < W2 > (self , n : Stream < 'a , K , W2 , C , N >) -> Stream < 'a , (K , V1) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("anti_join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: AntiJoin (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , K : Eq + Hash , V , N : Location > Stream < 'a , (K , V) , Bounded , Tick , N > { pub fn fold_keyed < A , I : Fn () -> A + 'a , F : Fn (& mut A , V) + 'a > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , A) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FoldKeyed { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce_keyed < F : Fn (& mut V , V) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , V) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: ReduceKeyed { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } pub fn get_this_crate () -> TokenStream { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , Span :: call_site ()) ; quote ! { # ident } } } } pub fn serialize_bincode < T : Serialize > (is_demux : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if is_demux { parse_quote ! { map (| (id , data) | { (id , # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into ()) }) } } else { parse_quote ! { map (| data | { # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into () }) } } } pub fn deserialize_bincode < T : DeserializeOwned > (tagged : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if tagged { parse_quote ! { map (| res | { let (id , b) = res . unwrap () ; (id , # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& b) . unwrap ()) }) } } else { parse_quote ! { map (| res | { # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& res . unwrap ()) . unwrap () }) } } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn send_bincode < N2 : Location , CoreType > (self , other : & N2 ,) -> Stream < 'a , N :: Out < CoreType > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T > , CoreType : Serialize + DeserializeOwned , { let serialize_pipeline = Some (serialize_bincode :: < CoreType > (N :: is_demux ())) ; let deserialize_pipeline = Some (deserialize_bincode :: < CoreType > (N :: is_tagged ())) ; Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bytes < N2 : Location > (self , other : & N2 ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T > , { Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline : None , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline : if N :: is_tagged () { Some (parse_quote ! (map (| (id , b) | (id , b . unwrap () . freeze ())))) } else { Some (parse_quote ! (map (| b | b . unwrap () . freeze ()))) } , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bincode_interleaved < N2 : Location , Tag , CoreType > (self , other : & N2 ,) -> Stream < 'a , CoreType , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T , Out < CoreType > = (Tag , CoreType) > , CoreType : Serialize + DeserializeOwned , { self . send_bincode :: < N2 , CoreType > (other) . map (q ! (| (_ , b) | b)) } pub fn send_bytes_interleaved < N2 : Location , Tag > (self , other : & N2 ,) -> Stream < 'a , Bytes , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T , Out < Bytes > = (Tag , Bytes) > , { self . send_bytes :: < N2 > (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bincode < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < T > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) > , T : Clone + Serialize + DeserializeOwned , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bincode (other) } pub fn broadcast_bincode_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , T , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) , Out < T > = (Tag , T) > + 'a , T : Clone + Serialize + DeserializeOwned , { self . broadcast_bincode (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bytes < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) > + 'a , T : Clone , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bytes (other) } pub fn broadcast_bytes_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , Bytes , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) , Out < Bytes > = (Tag , Bytes) > + 'a , T : Clone , { self . broadcast_bytes (other) . map (q ! (| (_ , b) | b)) } } } pub use stream :: { Bounded , NoTick , Stream , Tick , Unbounded } ; pub mod singleton { pub use std :: cell :: RefCell ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use crate :: builder :: FlowLeaves ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial , CycleComplete } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: Stream ; pub use crate :: singleton :: CrossResult ; # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Singleton < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Singleton :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } pub use crate :: singleton :: Singleton ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Singleton { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleComplete < 'a > for Singleton < 'a , T , Bounded , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleCollectionWithInitial < 'a > for Singleton < 'a , T , Bounded , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , initial : Self , l : LocationId ,) -> Self { Singleton :: new (l , ir_leaves , HfPlusNode :: Union (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , }) , initial . ir_node . into_inner () . into () ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Singleton < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Singleton { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , U , W , C , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (Self :: other_ir_node (other)) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Singleton < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CrossSingleton (Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , Box :: new (HfPlusNode :: Unpersist (Box :: new (Self :: other_ir_node (other)))) ,))) ,) } } pub use crate :: singleton :: Optional ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Optional { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } pub fn some (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: new (singleton . location_kind , singleton . ir_leaves , singleton . ir_node . into_inner () ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > From < Singleton < 'a , T , W , C , N > > for Optional < 'a , T , W , C , N > { fn from (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: some (singleton) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Optional < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Optional { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn into_stream (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , Tick , N > > ,) -> Optional < 'a , (T , O) , Bounded , Tick , N > where O : Clone , { let other : Optional < 'a , O , Bounded , Tick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn union (self , other : Optional < 'a , T , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Optional < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_samples (self) -> Stream < 'a , T , Unbounded , NoTick , N > { self . latest_tick () . all_ticks () } pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . latest_tick () . continue_if (samples . first ()) . latest () . tick_samples () } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Unbounded , NoTick , N > > ,) -> Optional < 'a , (T , O) , Unbounded , NoTick , N > where O : Clone , { let other : Optional < 'a , O , Unbounded , NoTick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } self . latest_tick () . cross_singleton (other . latest_tick ()) . latest () } } } pub use singleton :: { Optional , Singleton } ; pub mod location { pub use std :: marker :: PhantomData ; pub use crate :: location :: LocationId ; pub use crate :: location :: Location ; pub use crate :: location :: Process ; # [cfg (stageleft_macro)] impl < P > Clone for Process < P > { fn clone (& self) -> Self { Process { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < P > Location for Process < P > { fn id (& self) -> LocationId { LocationId :: Process (self . id) } } pub use crate :: location :: Cluster ; # [cfg (stageleft_macro)] impl < C > Clone for Cluster < C > { fn clone (& self) -> Self { Cluster { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < C > Location for Cluster < C > { fn id (& self) -> LocationId { LocationId :: Cluster (self . id) } } pub use crate :: location :: CanSend ; # [cfg (stageleft_macro)] impl < P1 , P2 > CanSend < Process < P2 > > for Process < P1 > { type In < T > = T ; type Out < T > = T ; fn is_demux () -> bool { false } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < P1 , C2 > CanSend < Cluster < C2 > > for Process < P1 > { type In < T > = (u32 , T) ; type Out < T > = T ; fn is_demux () -> bool { true } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < C1 , P2 > CanSend < Process < P2 > > for Cluster < C1 > { type In < T > = T ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { false } fn is_tagged () -> bool { true } } # [cfg (stageleft_macro)] impl < C1 , C2 > CanSend < Cluster < C2 > > for Cluster < C1 > { type In < T > = (u32 , T) ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { true } fn is_tagged () -> bool { true } } } pub use location :: { Cluster , Process } ; pub mod deploy { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use stageleft :: Quoted ; pub mod graphs { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use super :: { LocalDeploy , Node , ProcessSpec } ; pub use crate :: deploy :: graphs :: SingleProcessGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for SingleProcessGraph { type Process = SingleNode ; type Cluster = SingleNode ; type Meta = () ; type GraphId = () ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { SingleNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { SingleNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , SingleProcessGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> SingleNode { SingleNode { } } } pub use crate :: deploy :: graphs :: SingleNode ; # [cfg (stageleft_macro)] impl Node for SingleNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } pub use crate :: deploy :: graphs :: MultiGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for MultiGraph { type Process = MultiNode ; type Cluster = MultiNode ; type Meta = () ; type GraphId = usize ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { MultiNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { MultiNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , MultiGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> MultiNode { MultiNode { } } } pub use crate :: deploy :: graphs :: MultiNode ; # [cfg (stageleft_macro)] impl Node for MultiNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } } pub use graphs :: * ; pub use crate :: deploy :: LocalDeploy ; pub use crate :: deploy :: Deploy ; # [cfg (stageleft_macro)] impl < 'a , T : Deploy < 'a , Process = N , Cluster = C , Meta = M , GraphId = R > , N : Node < Meta = M > , C : Node < Meta = M > , M : Default , R , > LocalDeploy < 'a > for T { type Process = N ; type Cluster = C ; type Meta = M ; type GraphId = R ; fn has_trivial_node () -> bool { < T as Deploy < 'a > > :: has_trivial_node () } fn trivial_process (id : usize) -> Self :: Process { < T as Deploy < 'a > > :: trivial_process (id) } fn trivial_cluster (id : usize) -> Self :: Cluster { < T as Deploy < 'a > > :: trivail_cluster (id) } } pub use crate :: deploy :: ProcessSpec ; pub use crate :: deploy :: ClusterSpec ; pub use crate :: deploy :: Node ; } pub use deploy :: { ClusterSpec , Deploy , ProcessSpec } ; pub mod cycle { pub use std :: marker :: PhantomData ; pub use crate :: builder :: FlowLeaves ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: cycle :: CycleComplete ; pub use crate :: cycle :: CycleCollection ; pub use crate :: cycle :: CycleCollectionWithInitial ; pub use crate :: cycle :: HfCycle ; # [cfg (stageleft_macro)] impl < 'a , S : CycleComplete < 'a > > HfCycle < 'a , S > { pub fn complete (self , stream : S) { let ident = self . ident ; S :: complete (stream , ident) } } } pub use cycle :: HfCycle ; pub mod builder { pub use std :: cell :: RefCell ; pub use std :: collections :: HashMap ; pub use std :: marker :: PhantomData ; pub use std :: rc :: Rc ; pub use std :: time :: Duration ; pub use hydroflow :: futures :: stream :: Stream as FuturesStream ; pub use hydroflow :: { tokio , tokio_stream } ; pub use internal :: TokenStream ; pub use proc_macro2 :: Span ; pub use quote :: quote ; pub use runtime_support :: FreeVariable ; pub use stageleft :: * ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Cluster , Location , LocationId , Process } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: { HfCycle , Optional , RuntimeContext , Singleton , Stream } ; pub mod built { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use hydroflow_lang :: graph :: { eliminate_extra_unions_tees , HydroflowGraph } ; pub use super :: deploy :: { DeployFlow , DeployResult } ; pub use crate :: deploy :: { ClusterSpec , Deploy , LocalDeploy , ProcessSpec } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Cluster , Process } ; pub use crate :: HfCompiled ; pub use crate :: builder :: built :: BuiltFlow ; # [cfg (stageleft_macro)] impl < 'a > Drop for BuiltFlow < 'a > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped BuiltFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn ir (& self) -> & Vec < HfPlusLeaf < 'a > > { & self . ir } pub fn optimize_with (mut self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> BuiltFlow < 'a > { self . used = true ; BuiltFlow { ir : f (std :: mem :: take (& mut self . ir)) , processes : std :: mem :: take (& mut self . processes) , clusters : std :: mem :: take (& mut self . clusters) , used : false , _phantom : PhantomData , } } } pub fn build_inner (ir : & mut Vec < HfPlusLeaf >) -> BTreeMap < usize , HydroflowGraph > { let mut builders = BTreeMap :: new () ; let mut built_tees = HashMap :: new () ; let mut next_stmt_id = 0 ; for leaf in ir { leaf . emit (& mut builders , & mut built_tees , & mut next_stmt_id) ; } builders . into_iter () . map (| (k , v) | { let (mut flat_graph , _ , _) = v . build () ; eliminate_extra_unions_tees (& mut flat_graph) ; (k , flat_graph) }) . collect () } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn compile_no_network < D : LocalDeploy < 'a > > (mut self) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; HfCompiled { hydroflow_ir : build_inner (& mut self . ir) , extra_stmts : BTreeMap :: new () , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> BuiltFlow < 'a > { self . optimize_with (crate :: persist_pullup :: persist_pullup) } fn into_deploy < D : LocalDeploy < 'a > > (mut self) -> DeployFlow < 'a , D > { self . used = true ; let processes = if D :: has_trivial_node () { self . processes . iter () . map (| id | (* id , D :: trivial_process (* id))) . collect () } else { HashMap :: new () } ; let clusters = if D :: has_trivial_node () { self . clusters . iter () . map (| id | (* id , D :: trivial_cluster (* id))) . collect () } else { HashMap :: new () } ; DeployFlow { ir : std :: mem :: take (& mut self . ir) , nodes : processes , clusters , used : false , _phantom : PhantomData , } } pub fn with_process < P , D : LocalDeploy < 'a > > (self , process : & Process < P > , spec : impl ProcessSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_process (process , spec) } pub fn with_cluster < C , D : LocalDeploy < 'a > > (self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_cluster (cluster , spec) } pub fn compile < D : Deploy < 'a > + 'a > (self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . into_deploy :: < D > () . compile (env) } pub fn deploy < D : Deploy < 'a , CompileEnv = () > + 'a > (self , env : & mut D :: InstantiateEnv ,) -> DeployResult < 'a , D > { self . into_deploy :: < D > () . deploy (env) } } } pub mod deploy { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use proc_macro2 :: Span ; pub use stageleft :: Quoted ; pub use super :: built :: build_inner ; pub use crate :: deploy :: { LocalDeploy , Node } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: { Cluster , ClusterSpec , Deploy , HfCompiled , Process , ProcessSpec } ; pub use crate :: builder :: deploy :: DeployFlow ; # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > Drop for DeployFlow < 'a , D > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped DeployFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > DeployFlow < 'a , D > { pub fn with_process < P > (mut self , process : & Process < P > , spec : impl ProcessSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < P > () . to_string () ; self . nodes . insert (process . id , spec . build (process . id , & tag_name)) ; self } pub fn with_cluster < C > (mut self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < C > () . to_string () ; self . clusters . insert (cluster . id , spec . build (cluster . id , & tag_name)) ; self } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployFlow < 'a , D > { pub fn compile (mut self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; let mut seen_tees : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | leaf . compile_network :: < D > (env , & mut seen_tees , & self . nodes , & self . clusters)) . collect () ; let extra_stmts = self . extra_stmts (env) ; HfCompiled { hydroflow_ir : build_inner (& mut ir_leaves_networked) , extra_stmts , _phantom : PhantomData , } } fn extra_stmts (& self , env : & < D as Deploy < 'a > > :: CompileEnv) -> BTreeMap < usize , Vec < syn :: Stmt > > { let all_locations_count = self . nodes . len () + self . clusters . len () ; let mut extra_stmts : BTreeMap < usize , Vec < syn :: Stmt > > = BTreeMap :: new () ; for & c_id in self . clusters . keys () { let self_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , c_id) , Span :: call_site () ,) ; let self_id_expr = D :: cluster_self_id (env) . splice () ; extra_stmts . entry (c_id) . or_default () . push (syn :: parse_quote ! { let # self_id_ident = # self_id_expr ; }) ; for other_location in 0 .. all_locations_count { let other_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , c_id) , Span :: call_site () ,) ; let other_id_expr = D :: cluster_ids (env , c_id) . splice () ; extra_stmts . entry (other_location) . or_default () . push (syn :: parse_quote ! { let # other_id_ident = # other_id_expr ; }) ; } } extra_stmts } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a , CompileEnv = () > > DeployFlow < 'a , D > { # [must_use] pub fn deploy (mut self , env : & mut D :: InstantiateEnv) -> DeployResult < 'a , D > { self . used = true ; let mut seen_tees_instantiate : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | { leaf . compile_network :: < D > (& () , & mut seen_tees_instantiate , & self . nodes , & self . clusters ,) }) . collect () ; let mut compiled = build_inner (& mut ir_leaves_networked) ; let mut extra_stmts = self . extra_stmts (& ()) ; let mut meta = D :: Meta :: default () ; let (mut processes , mut clusters) = (std :: mem :: take (& mut self . nodes) . into_iter () . map (| (node_id , node) | { node . instantiate (env , & mut meta , compiled . remove (& node_id) . unwrap () , extra_stmts . remove (& node_id) . unwrap_or_default () ,) ; (node_id , node) }) . collect :: < HashMap < _ , _ > > () , std :: mem :: take (& mut self . clusters) . into_iter () . map (| (cluster_id , cluster) | { cluster . instantiate (env , & mut meta , compiled . remove (& cluster_id) . unwrap () , extra_stmts . remove (& cluster_id) . unwrap_or_default () ,) ; (cluster_id , cluster) }) . collect :: < HashMap < _ , _ > > () ,) ; for node in processes . values_mut () { node . update_meta (& meta) ; } for cluster in clusters . values_mut () { cluster . update_meta (& meta) ; } let mut seen_tees_connect = HashMap :: new () ; for leaf in ir_leaves_networked { leaf . connect_network (& mut seen_tees_connect) ; } DeployResult { processes , clusters , } } } pub use crate :: builder :: deploy :: DeployResult ; # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployResult < 'a , D > { pub fn get_process < P > (& self , p : & Process < P >) -> & D :: Process { let id = match p . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . processes . get (& id) . unwrap () } pub fn get_cluster < C > (& self , c : & Cluster < C >) -> & D :: Cluster { let id = match c . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . clusters . get (& id) . unwrap () } } } # [doc = " Tracks the leaves of the dataflow IR. This is referenced by"] # [doc = " `Stream` and `HfCycle` to build the IR. The inner option will"] # [doc = " be set to `None` when this builder is finalized."] pub type FlowLeaves < 'a > = Rc < RefCell < Option < Vec < HfPlusLeaf < 'a > > > > > ; pub use crate :: builder :: ClusterIds ; # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Vec < u32 > > for ClusterIds < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , & 'a Vec < u32 > > for ClusterIds < 'a > { } # [derive (Copy , Clone)] pub struct ClusterSelfId < 'a > { pub id : usize , pub _phantom : PhantomData < & 'a mut & 'a u32 > , } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < u32 > for ClusterSelfId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , u32 > for ClusterSelfId < 'a > { } pub use crate :: builder :: FlowBuilder ; # [cfg (stageleft_macro)] impl < 'a > Drop for FlowBuilder < 'a > { fn drop (& mut self) { if ! self . finalized { panic ! ("Dropped FlowBuilder without finalizing, you may have forgotten to call `with_default_optimize`, `optimize_with`, or `finalize`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > QuotedContext for FlowBuilder < 'a > { fn create () -> Self { FlowBuilder :: new () } } # [cfg (stageleft_macro)] impl < 'a > FlowBuilder < 'a > { # [allow (clippy :: new_without_default)] pub fn new () -> FlowBuilder < 'a > { FlowBuilder { ir_leaves : Rc :: new (RefCell :: new (Some (Vec :: new ()))) , nodes : RefCell :: new (vec ! []) , clusters : RefCell :: new (vec ! []) , cycle_ids : RefCell :: new (HashMap :: new ()) , next_node_id : RefCell :: new (0) , finalized : false , _phantom : PhantomData , } } pub fn finalize (mut self) -> built :: BuiltFlow < 'a > { self . finalized = true ; built :: BuiltFlow { ir : self . ir_leaves . borrow_mut () . take () . unwrap () , processes : self . nodes . replace (vec ! []) , clusters : self . clusters . replace (vec ! []) , used : false , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> built :: BuiltFlow < 'a > { self . finalize () . with_default_optimize () } pub fn optimize_with (self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> built :: BuiltFlow < 'a > { self . finalize () . optimize_with (f) } pub fn ir_leaves (& self) -> & FlowLeaves < 'a > { & self . ir_leaves } pub fn process < P > (& self) -> Process < P > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . nodes . borrow_mut () . push (id) ; Process { id , _phantom : PhantomData , } } pub fn cluster < C > (& self) -> Cluster < C > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . clusters . borrow_mut () . push (id) ; Cluster { id , _phantom : PhantomData , } } pub fn runtime_context (& self) -> RuntimeContext < 'a > { RuntimeContext { _phantom : PhantomData , } } pub fn cluster_members < C > (& self , cluster : & Cluster < C > ,) -> impl Quoted < 'a , & 'a Vec < u32 > > + Copy + 'a { ClusterIds { id : cluster . id , _phantom : PhantomData , } } pub fn cluster_self_id < C > (& self , cluster : & Cluster < C >) -> impl Quoted < 'a , u32 > + Copy + 'a { ClusterSelfId { id : cluster . id , _phantom : PhantomData , } } pub fn spin < L : Location > (& self , on : & L) -> Stream < 'a , () , Unbounded , NoTick , L > { Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Spin () , location_kind : on . id () , })) ,) } pub fn spin_batch < L : Location > (& self , on : & L , batch_size : impl Quoted < 'a , usize > + Copy + 'a ,) -> Stream < 'a , () , Bounded , Tick , L > { self . spin (on) . flat_map (q ! (move | _ | 0 .. batch_size)) . map (q ! (| _ | ())) . tick_batch () } pub fn source_stream < T , E : FuturesStream < Item = T > + Unpin , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Unbounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Stream (e . into ()) , location_kind : on . id () , })) ,) } pub fn source_iter < T , E : IntoIterator < Item = T > , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Bounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , })) ,) } pub fn singleton < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Singleton < 'a , T , Bounded , NoTick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Singleton :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,)))) ,) } pub fn singleton_first_tick < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Optional < 'a , T , Bounded , Tick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,) } pub fn source_interval < L : Location > (& self , on : & L , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , () , Unbounded , NoTick , L > { let interval = interval . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : on . id () , })) ,) } pub fn source_interval_delayed < L : Location > (& self , on : & L , delay : impl Quoted < 'a , Duration > + Copy + 'a , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , tokio :: time :: Instant , Unbounded , NoTick , L > { self . source_stream (on , q ! (tokio_stream :: wrappers :: IntervalStream :: new (tokio :: time :: interval_at (tokio :: time :: Instant :: now () + delay , interval))) ,) . tick_batch () . first () . latest () } pub fn cycle < S : CycleCollection < 'a > > (& self , on : & S :: Location) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , on . id ()) ,) } pub fn cycle_with_initial < S : CycleCollectionWithInitial < 'a > > (& self , on : & S :: Location , initial : S ,) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , initial , on . id ()) ,) } } } pub use builder :: FlowBuilder ; pub mod ir { pub use core :: panic ; pub use std :: cell :: RefCell ; pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow_lang :: graph :: FlatGraphBuilder ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: ToTokens ; pub use syn :: parse_quote ; pub use crate :: deploy :: Deploy ; pub use crate :: location :: LocationId ; pub use crate :: ir :: DebugExpr ; # [cfg (stageleft_macro)] impl From < syn :: Expr > for DebugExpr { fn from (expr : syn :: Expr) -> DebugExpr { DebugExpr (expr) } } # [cfg (stageleft_macro)] impl Deref for DebugExpr { type Target = syn :: Expr ; fn deref (& self) -> & Self :: Target { & self . 0 } } # [cfg (stageleft_macro)] impl ToTokens for DebugExpr { fn to_tokens (& self , tokens : & mut TokenStream) { self . 0 . to_tokens (tokens) ; } } # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugExpr { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "{}" , self . 0 . to_token_stream ()) } } pub use crate :: ir :: DebugInstantiate ; # [cfg (stageleft_macro)] impl < 'a > std :: fmt :: Debug for DebugInstantiate < 'a > { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<network instantiate>") } } pub use crate :: ir :: DebugPipelineFn ; # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugPipelineFn { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<function>") } } pub use crate :: ir :: HfPlusSource ; pub use crate :: ir :: HfPlusLeaf ; # [cfg (stageleft_macro)] impl < 'a > HfPlusLeaf < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . compile_network :: < D > (compile_env , s , nodes , clusters) ; } , seen_tees ,) } pub fn connect_network (self , seen_tees : & mut SeenTees < 'a >) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . connect_network (s) ; } , seen_tees ,) } pub fn transform_children (self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) -> HfPlusLeaf < 'a > { match self { HfPlusLeaf :: ForEach { f , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: ForEach { f , input } } HfPlusLeaf :: DestSink { sink , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: DestSink { sink , input } } HfPlusLeaf :: CycleSink { ident , location_kind , mut input , } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: CycleSink { ident , location_kind , input , } } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) { match self { HfPlusLeaf :: ForEach { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> for_each (# f) ; }) ; } HfPlusLeaf :: DestSink { sink , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink) ; }) ; } HfPlusLeaf :: CycleSink { ident , location_kind , input , } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; assert_eq ! (input_location_id , * location_id , "cycle_sink location mismatch") ; graph_builders . entry (* location_id) . or_default () . add_statement (parse_quote ! { # ident = # input_ident ; }) ; } } } } pub use crate :: ir :: HfPlusNode ; pub type SeenTees < 'a > = HashMap < * const RefCell < HfPlusNode < 'a > > , Rc < RefCell < HfPlusNode < 'a > > > > ; # [cfg (stageleft_macro)] impl < 'a > HfPlusNode < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (& mut self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) { self . transform_children (| n , s | n . compile_network :: < D > (compile_env , s , nodes , clusters) , seen_tees ,) ; if let HfPlusNode :: Network { from_location , to_location , instantiate_fn , .. } = self { let (sink_expr , source_expr , connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { let ((sink , source) , connect_fn) = match (from_location , to_location) { (LocationId :: Process (from) , LocationId :: Process (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: o2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Process (from) , LocationId :: Cluster (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: o2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Process (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: m2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Cluster (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: m2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } } ; (sink , source , connect_fn) } DebugInstantiate :: Finalized (_ , _ , _) => panic ! ("network already finalized") , } ; * instantiate_fn = DebugInstantiate :: Finalized (sink_expr , source_expr , connect_fn) ; } } pub fn connect_network (& mut self , seen_tees : & mut SeenTees < 'a >) { self . transform_children (| n , s | n . connect_network (s) , seen_tees) ; if let HfPlusNode :: Network { instantiate_fn , .. } = self { match instantiate_fn { DebugInstantiate :: Building () => panic ! ("network not built") , DebugInstantiate :: Finalized (_ , _ , ref connect_fn) => { connect_fn () ; } } } } pub fn transform_children (& mut self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) { match self { HfPlusNode :: Placeholder => { panic ! () ; } HfPlusNode :: Source { .. } => { } HfPlusNode :: CycleSource { .. } => { } HfPlusNode :: Tee { inner } => { if let Some (transformed) = seen_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { * inner = transformed . clone () ; } else { let transformed_cell = Rc :: new (RefCell :: new (HfPlusNode :: Placeholder)) ; seen_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , transformed_cell . clone () ,) ; let mut orig = inner . replace (HfPlusNode :: Placeholder) ; transform (& mut orig , seen_tees) ; * transformed_cell . borrow_mut () = orig ; * inner = transformed_cell ; } } HfPlusNode :: Persist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Unpersist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Delta (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Union (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossProduct (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossSingleton (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Join (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Difference (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: AntiJoin (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Map { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FlatMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Filter { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FilterMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Sort (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: DeferTick (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Enumerate (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Inspect { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Unique (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Fold { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FoldKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Reduce { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: ReduceKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Network { input , .. } => { transform (input . as_mut () , seen_tees) ; } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) -> (syn :: Ident , usize) { match self { HfPlusNode :: Placeholder => { panic ! () } HfPlusNode :: Persist (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let persist_id = * next_stmt_id ; * next_stmt_id += 1 ; let persist_ident = syn :: Ident :: new (& format ! ("stream_{}" , persist_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # persist_ident = # inner_ident -> persist ::<'static > () ; }) ; (persist_ident , location) } HfPlusNode :: Unpersist (_) => { panic ! ("Unpersist is a marker node and should have been optimized away. This is likely a compiler bug.") } HfPlusNode :: Delta (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let delta_id = * next_stmt_id ; * next_stmt_id += 1 ; let delta_ident = syn :: Ident :: new (& format ! ("stream_{}" , delta_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # delta_ident = # inner_ident -> multiset_delta () ; }) ; (delta_ident , location) } HfPlusNode :: Source { source , location_kind , } => { let source_id = * next_stmt_id ; * next_stmt_id += 1 ; let source_ident = syn :: Ident :: new (& format ! ("stream_{}" , source_id) , Span :: call_site ()) ; let source_stmt = match source { HfPlusSource :: Stream (expr) => { parse_quote ! { # source_ident = source_stream (# expr) ; } } HfPlusSource :: Iter (expr) => { parse_quote ! { # source_ident = source_iter (# expr) ; } } HfPlusSource :: Interval (expr) => { parse_quote ! { # source_ident = source_interval (# expr) ; } } HfPlusSource :: Spin () => { parse_quote ! { # source_ident = spin () ; } } } ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; graph_builders . entry (* location_id) . or_default () . add_statement (source_stmt) ; (source_ident , * location_id) } HfPlusNode :: CycleSource { ident , location_kind , } => { let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; (ident . clone () , * location_id) } HfPlusNode :: Tee { inner } => { if let Some (ret) = built_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { ret . clone () } else { let (inner_ident , inner_location_id) = inner . borrow () . emit (graph_builders , built_tees , next_stmt_id) ; let tee_id = * next_stmt_id ; * next_stmt_id += 1 ; let tee_ident = syn :: Ident :: new (& format ! ("stream_{}" , tee_id) , Span :: call_site ()) ; let builder = graph_builders . entry (inner_location_id) . or_default () ; builder . add_statement (parse_quote ! { # tee_ident = # inner_ident -> tee () ; }) ; built_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , (tee_ident . clone () , inner_location_id) ,) ; (tee_ident , inner_location_id) } } HfPlusNode :: Union (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "union inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let union_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # union_ident = union () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [0] # union_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # union_ident ; }) ; (union_ident , left_location_id) } HfPlusNode :: CrossSingleton (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "cross_singleton inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let cross_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # cross_ident = cross_singleton () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [input] # cross_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [single] # cross_ident ; }) ; (cross_ident , left_location_id) } HfPlusNode :: CrossProduct (..) | HfPlusNode :: Join (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: CrossProduct (..)) { parse_quote ! (cross_join_multiset) } else { parse_quote ! (join_multiset) } ; let (HfPlusNode :: CrossProduct (left , right) | HfPlusNode :: Join (left , right)) = self else { unreachable ! () } ; let (left_inner , left_was_persist) = if let HfPlusNode :: Persist (left) = left . as_ref () { (left , true) } else { (left , false) } ; let (right_inner , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left_inner . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right_inner . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "join / cross product inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; match (left_was_persist , right_was_persist) { (true , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'static > () ; }) ; } (true , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'tick > () ; }) ; } (false , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } (false , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } } ; builder . add_statement (parse_quote ! { # left_ident -> [0] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Difference (..) | HfPlusNode :: AntiJoin (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Difference (..)) { parse_quote ! (difference_multiset) } else { parse_quote ! (anti_join_multiset) } ; let (HfPlusNode :: Difference (left , right) | HfPlusNode :: AntiJoin (left , right)) = self else { unreachable ! () } ; let (right , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "difference / anti join inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; if right_was_persist { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } else { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } builder . add_statement (parse_quote ! { # left_ident -> [pos] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [neg] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Map { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let map_id = * next_stmt_id ; * next_stmt_id += 1 ; let map_ident = syn :: Ident :: new (& format ! ("stream_{}" , map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # map_ident = # input_ident -> map (# f) ; }) ; (map_ident , input_location_id) } HfPlusNode :: FlatMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let flat_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let flat_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , flat_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # flat_map_ident = # input_ident -> flat_map (# f) ; }) ; (flat_map_ident , input_location_id) } HfPlusNode :: Filter { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_ident = # input_ident -> filter (# f) ; }) ; (filter_ident , input_location_id) } HfPlusNode :: FilterMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_map_ident = # input_ident -> filter_map (# f) ; }) ; (filter_map_ident , input_location_id) } HfPlusNode :: Sort (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sort_id = * next_stmt_id ; * next_stmt_id += 1 ; let sort_ident = syn :: Ident :: new (& format ! ("stream_{}" , sort_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # sort_ident = # input_ident -> sort () ; }) ; (sort_ident , input_location_id) } HfPlusNode :: DeferTick (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let defer_tick_id = * next_stmt_id ; * next_stmt_id += 1 ; let defer_tick_ident = syn :: Ident :: new (& format ! ("stream_{}" , defer_tick_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # defer_tick_ident = # input_ident -> defer_tick_lazy () ; }) ; (defer_tick_ident , input_location_id) } HfPlusNode :: Enumerate (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let enumerate_id = * next_stmt_id ; * next_stmt_id += 1 ; let enumerate_ident = syn :: Ident :: new (& format ! ("stream_{}" , enumerate_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # enumerate_ident = # input_ident -> enumerate () ; }) ; (enumerate_ident , input_location_id) } HfPlusNode :: Inspect { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let inspect_id = * next_stmt_id ; * next_stmt_id += 1 ; let inspect_ident = syn :: Ident :: new (& format ! ("stream_{}" , inspect_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # inspect_ident = # input_ident -> inspect (# f) ; }) ; (inspect_ident , input_location_id) } HfPlusNode :: Unique (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let unique_id = * next_stmt_id ; * next_stmt_id += 1 ; let unique_ident = syn :: Ident :: new (& format ! ("stream_{}" , unique_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # unique_ident = # input_ident -> unique ::<'tick > () ; }) ; (unique_ident , input_location_id) } HfPlusNode :: Fold { .. } | HfPlusNode :: FoldKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Fold { .. }) { parse_quote ! (fold) } else { parse_quote ! (fold_keyed) } ; let (HfPlusNode :: Fold { init , acc , input } | HfPlusNode :: FoldKeyed { init , acc , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let fold_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'static > (# init , # acc) ; }) ; } else { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'tick > (# init , # acc) ; }) ; } (fold_ident , input_location_id) } HfPlusNode :: Reduce { .. } | HfPlusNode :: ReduceKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Reduce { .. }) { parse_quote ! (reduce) } else { parse_quote ! (reduce_keyed) } ; let (HfPlusNode :: Reduce { f , input } | HfPlusNode :: ReduceKeyed { f , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let reduce_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'static > (# f) ; }) ; } else { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'tick > (# f) ; }) ; } (reduce_ident , input_location_id) } HfPlusNode :: Network { from_location : _ , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input , } => { let (sink_expr , source_expr , _connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { panic ! ("Expected the network to be finalized") } DebugInstantiate :: Finalized (sink , source , connect_fn) => { (sink , source , connect_fn) } } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sender_builder = graph_builders . entry (input_location_id) . or_default () ; if let Some (serialize_pipeline) = serialize_pipeline { sender_builder . add_statement (parse_quote ! { # input_ident -> # serialize_pipeline -> dest_sink (# sink_expr) ; }) ; } else { sender_builder . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink_expr) ; }) ; } let to_id = match to_location { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let receiver_builder = graph_builders . entry (* to_id) . or_default () ; let receiver_stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let receiver_stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , receiver_stream_id) , Span :: call_site ()) ; if let Some (deserialize_pipeline) = deserialize_pipeline { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) -> # deserialize_pipeline ; }) ; } else { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) ; }) ; } (receiver_stream_ident , * to_id) } } } } } pub mod persist_pullup { pub use std :: cell :: RefCell ; pub use std :: collections :: HashSet ; pub use std :: ops :: Deref ; pub use crate :: ir :: * ; pub fn persist_pullup_node < 'a > (node : & mut HfPlusNode < 'a > , seen_tees : & mut SeenTees < 'a > , persist_pulled_tees : & mut HashSet < * const RefCell < HfPlusNode < 'a > > > ,) { node . transform_children (| n , s | persist_pullup_node (n , s , persist_pulled_tees) , seen_tees ,) ; match node { HfPlusNode :: Unpersist (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Unpersist (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Delta (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Delta (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Tee { inner } => { if persist_pulled_tees . contains (& (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >)) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } else { let inner_borrow = inner . borrow () ; if let HfPlusNode :: Persist (_) = inner_borrow . deref () { drop (inner_borrow) ; persist_pulled_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >) ; if let HfPlusNode :: Persist (box behind_persist) = inner . replace (HfPlusNode :: Placeholder) { * inner . borrow_mut () = behind_persist ; } else { unreachable ! () } * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } } } HfPlusNode :: Map { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Map { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Map { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: FlatMap { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: FlatMap { f , input : deref!(HfPlusNode :: Persist (behind_persist)) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: FlatMap { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Filter { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Filter { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Filter { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Network { input : box HfPlusNode :: Persist (_) , .. } => { if let HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Union (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Union (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Union (left , right))) ; } else { unreachable ! () } } HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: CrossProduct (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,) ,)))) ; } else { unreachable ! () } } HfPlusNode :: Join (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Join (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: Join (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,))))) ; } else { unreachable ! () } } _ => { } } } pub fn persist_pullup (ir : Vec < HfPlusLeaf >) -> Vec < HfPlusLeaf > { let mut seen_tees = Default :: default () ; let mut persist_pulled_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| n , s | persist_pullup_node (n , s , & mut persist_pulled_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn persist_pullup_through_map () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } # [test] fn persist_pullup_behind_tee () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; let before_tee = flow . source_iter (& process , q ! (0 .. 10)) . tick_batch () . persist () ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } } } pub mod profiler { pub use std :: cell :: RefCell ; pub use hydroflow :: futures :: channel :: mpsc :: UnboundedSender ; pub use stageleft :: * ; pub use crate as hydroflow_plus ; pub use crate :: ir :: * ; pub use crate :: RuntimeContext ; pub fn increment_counter (count : & mut u64) { * count += 1 ; } pub fn quoted_any_fn < 'a , F : Fn (& usize) + 'a , Q : IntoQuotedMut < 'a , F > > (q : Q) -> Q { q } # [doc = " Add a profiling node before each node to count the cardinality of its input"] pub fn add_profiling_node < 'a > (node : & mut HfPlusNode < 'a > , _context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > , id : & mut u32 , seen_tees : & mut SeenTees < 'a > ,) { let my_id = * id ; * id += 1 ; node . transform_children (| node , seen_tees | { add_profiling_node (node , _context , counters , counter_queue , id , seen_tees) } , seen_tees ,) ; let orig_node = std :: mem :: replace (node , HfPlusNode :: Placeholder) ; * node = HfPlusNode :: Inspect { f : quoted_any_fn (q ! ({ counter_queue . borrow () . unbounded_send ((my_id as usize , counters . borrow () [my_id as usize])) . unwrap () ; counters . borrow_mut () [my_id as usize] = 0 ; move | _ | { hydroflow_plus :: profiler :: increment_counter (& mut counters . borrow_mut () [my_id as usize] ,) ; } })) . splice () . into () , input : Box :: new (orig_node) , } } # [doc = " Count the cardinality of each input and periodically output to a file"] pub fn profiling < 'a > (ir : Vec < HfPlusLeaf < 'a > > , context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > ,) -> Vec < HfPlusLeaf < 'a > > { let mut id = 0 ; let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | { add_profiling_node (node , context , counters , counter_queue , & mut id , seen_tees) } , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn profiler_wrapping_all_operators () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let runtime_context = flow . runtime_context () ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (& built . ir ()) ; let counters = RuntimeData :: new ("Fake") ; let counter_queue = RuntimeData :: new ("Fake") ; let pushed_down = built . with_default_optimize () . optimize_with (| ir | super :: profiling (ir , runtime_context , counters , counter_queue)) ; insta :: assert_debug_snapshot ! (& pushed_down . ir ()) ; let _ = pushed_down . compile_no_network :: < MultiGraph > () ; } } } pub mod properties { pub use std :: collections :: HashSet ; pub use stageleft :: * ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , SeenTees } ; pub use crate :: properties :: PropertyDatabase ; # [doc = " Allows us to convert the hydroflow datatype for folds to a binary operation for the algebra"] # [doc = " property tests."] # [allow (dead_code)] pub fn convert_hf_to_binary < I , A : Default , F : Fn (& mut A , I) > (f : F) -> impl Fn (I , I) -> A { move | a , b | { let mut acc = Default :: default () ; f (& mut acc , a) ; f (& mut acc , b) ; acc } } # [cfg (stageleft_macro)] impl PropertyDatabase { # [doc = " Tags the expression as commutative."] pub fn add_commutative_tag < 'a , I , A , F : Fn (& mut A , I) , Q : Quoted < 'a , F > + Clone > (& mut self , expr : Q ,) -> Q { let expr_clone = expr . clone () ; self . commutative . insert (expr_clone . splice ()) ; expr } pub fn is_tagged_commutative (& self , expr : & syn :: Expr) -> bool { self . commutative . contains (expr) } } pub fn properties_optimize_node < 'a > (node : & mut HfPlusNode < 'a > , db : & PropertyDatabase , seen_tees : & mut SeenTees < 'a > ,) { node . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , seen_tees ,) ; match node { HfPlusNode :: ReduceKeyed { f , .. } if db . is_tagged_commutative (& f . 0) => { dbg ! ("IDENTIFIED COMMUTATIVE OPTIMIZATION for {:?}" , & f) ; } _ => { } } } pub fn properties_optimize < 'a > (ir : Vec < HfPlusLeaf < 'a > > , db : & PropertyDatabase ,) -> Vec < HfPlusLeaf < 'a > > { let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use super :: * ; use crate :: deploy :: SingleProcessGraph ; use crate :: FlowBuilder ; # [test] fn test_property_database () { let mut db = PropertyDatabase :: default () ; assert ! (! db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; let _ = db . add_commutative_tag (q ! (| a : & mut i32 , b : i32 | * a += b)) ; assert ! (db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; } # [test] fn test_property_optimized () { let flow = FlowBuilder :: new () ; let mut database = PropertyDatabase :: default () ; let process = flow . process :: < () > () ; let counter_func = q ! (| count : & mut i32 , _ | * count += 1) ; let _ = database . add_commutative_tag (counter_func) ; flow . source_iter (& process , q ! (vec ! [])) . map (q ! (| string : String | (string , ()))) . tick_batch () . fold_keyed (q ! (|| 0) , counter_func) . all_ticks () . for_each (q ! (| (string , count) | println ! ("{}: {}" , string , count))) ; let built = flow . finalize () . optimize_with (| ir | properties_optimize (ir , & database)) . with_default_optimize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let _ = built . compile_no_network :: < SingleProcessGraph > () ; } } } pub use crate :: RuntimeContext ; # [cfg (stageleft_macro)] impl Copy for RuntimeContext < '_ > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Context > for RuntimeContext < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (quote ! (& context))) } } pub use crate :: HfCompiled ; # [cfg (stageleft_macro)] impl < 'a , ID > HfCompiled < 'a , ID > { pub fn hydroflow_ir (& self) -> & BTreeMap < usize , HydroflowGraph > { & self . hydroflow_ir } } # [cfg (stageleft_macro)] impl < 'a > HfCompiled < 'a , usize > { pub fn with_dynamic_id (self , id : impl Quoted < 'a , usize >) -> HfBuiltWithId < 'a > { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; let mut conditioned_tokens = None ; for (subgraph_id , flat_graph) in self . hydroflow_ir { let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; let my_extra_stmts = self . extra_stmts . get (& subgraph_id) . cloned () . unwrap_or_default () ; if let Some (conditioned_tokens) = conditioned_tokens . as_mut () { * conditioned_tokens = syn :: parse_quote ! { # conditioned_tokens else if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } } ; } else { conditioned_tokens = Some (syn :: parse_quote ! { if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } }) ; } } let conditioned_tokens : TokenStream = conditioned_tokens . unwrap () ; let id = id . splice () ; HfBuiltWithId { tokens : syn :: parse_quote ! ({ let __given_id = # id ; # conditioned_tokens else { panic ! ("Invalid node id: {}" , __given_id) ; } }) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfCompiled < 'a , () > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfCompiled < 'a , () > { fn to_tokens (mut self) -> (Option < TokenStream > , Option < TokenStream >) { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; if self . hydroflow_ir . len () != 1 { panic ! ("Expected exactly one subgraph in the Hydroflow IR") ; } let flat_graph = self . hydroflow_ir . remove (& 0) . unwrap () ; let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; (None , Some (tokens)) } } pub use crate :: HfBuiltWithId ; # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfBuiltWithId < 'a > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfBuiltWithId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (self . tokens)) } }
[INFO] [stdout]   |
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] error: `box` patterns have been removed (feature `box_patterns`)
[INFO] [stdout]  --> /opt/rustwide/target/debug/build/hydroflow_plus/5672655b657d1e44/out/lib_pub.rs:1:93745
[INFO] [stdout]   |
[INFO] [stdout] 1 | ... { unreachable ! () } } HfPlusNode :: Filter { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Filter ...
[INFO] [stdout]   |                                                                   ^^^
[INFO] [stdout]   |
[INFO] [stdout]   = help: enable feature `deref_patterns` instead and...
[INFO] [stdout] help: ...if possible just remove keyword `box`...
[INFO] [stdout]   |
[INFO] [stdout] 1 - pub use std :: collections :: BTreeMap ; pub use std :: marker :: PhantomData ; pub use hydroflow :: scheduled :: context :: Context ; pub use hydroflow :: scheduled :: graph :: Hydroflow ; pub use hydroflow :: * ; pub use lang :: graph :: { partition_graph , HydroflowGraph } ; pub use proc_macro2 :: TokenStream ; pub use quote :: quote ; pub use stageleft :: runtime_support :: FreeVariable ; pub use stageleft :: Quoted ; pub mod runtime_support { pub use bincode ; } pub mod stream { pub use std :: cell :: RefCell ; pub use std :: hash :: Hash ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow :: bytes :: Bytes ; pub use hydroflow :: futures :: Sink ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: quote ; pub use serde :: de :: DeserializeOwned ; pub use serde :: Serialize ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use syn :: parse_quote ; pub use crate :: builder :: { ClusterIds , FlowLeaves } ; pub use crate :: cycle :: { CycleCollection , CycleComplete } ; pub use crate :: ir :: { DebugInstantiate , HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { CanSend , Location , LocationId } ; pub use crate :: { Cluster , Optional , Singleton } ; pub use crate :: stream :: Unbounded ; pub use crate :: stream :: Bounded ; pub use crate :: stream :: NoTick ; pub use crate :: stream :: Tick ; pub use crate :: stream :: Stream ; # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Stream { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Stream < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Stream { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , C , N > > ,) -> Stream < 'a , (T , O) , W , C , N > where O : Clone , { let other : Optional < 'a , O , Bounded , C , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn cross_product < O > (self , other : Stream < 'a , O , W , C , N >) -> Stream < 'a , (T , O) , W , C , N > where T : Clone , O : Clone , { if self . location_kind != other . location_kind { panic ! ("cross_product must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossProduct (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn union (self , other : Stream < 'a , T , W , C , N >) -> Stream < 'a , T , W , C , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn dest_sink < S : Unpin + Sink < T > + 'a > (self , sink : impl Quoted < 'a , S >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: DestSink { sink : sink . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn first (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } # [doc = " Allow this stream through if the other stream has elements, otherwise the output is empty."] pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } # [doc = " Allow this stream through if the other stream is empty, otherwise the output is empty."] pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn enumerate (self) -> Stream < 'a , (usize , T) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Enumerate (Box :: new (self . ir_node . into_inner ())) ,) } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn sort (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Ord , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Sort (Box :: new (self . ir_node . into_inner ())) ,) } pub fn count (self) -> Singleton < 'a , usize , Bounded , Tick , N > { self . fold (q ! (|| 0usize) , q ! (| count , _ | * count += 1)) } pub fn delta (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } pub fn unique (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Eq + Hash , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unique (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn tick_batch (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_prefix (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { self . tick_batch () . persist () } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn for_each < F : Fn (T) + 'a > (self , f : impl IntoQuotedMut < 'a , F >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: ForEach { input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , f : f . splice () . into () , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Unbounded , NoTick , N > { pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . tick_batch () . continue_if (samples . first ()) . all_ticks () } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Unbounded , NoTick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , C , N : Location > Stream < 'a , T , Bounded , C , N > { pub fn filter_not_in (self , other : Stream < 'a , T , Bounded , C , N >) -> Stream < 'a , T , Bounded , C , N > where T : Eq + Hash , { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Difference (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Stream < 'a , & T , W , C , N > { pub fn cloned (self) -> Stream < 'a , T , W , C , N > { self . map (q ! (| d | d . clone ())) } } # [cfg (stageleft_macro)] impl < 'a , K , V1 , W , C , N : Location > Stream < 'a , (K , V1) , W , C , N > { pub fn join < W2 , V2 > (self , n : Stream < 'a , (K , V2) , W2 , C , N > ,) -> Stream < 'a , (K , (V1 , V2)) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Join (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } pub fn anti_join < W2 > (self , n : Stream < 'a , K , W2 , C , N >) -> Stream < 'a , (K , V1) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("anti_join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: AntiJoin (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , K : Eq + Hash , V , N : Location > Stream < 'a , (K , V) , Bounded , Tick , N > { pub fn fold_keyed < A , I : Fn () -> A + 'a , F : Fn (& mut A , V) + 'a > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , A) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FoldKeyed { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce_keyed < F : Fn (& mut V , V) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , V) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: ReduceKeyed { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } pub fn get_this_crate () -> TokenStream { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , Span :: call_site ()) ; quote ! { # ident } } } } pub fn serialize_bincode < T : Serialize > (is_demux : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if is_demux { parse_quote ! { map (| (id , data) | { (id , # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into ()) }) } } else { parse_quote ! { map (| data | { # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into () }) } } } pub fn deserialize_bincode < T : DeserializeOwned > (tagged : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if tagged { parse_quote ! { map (| res | { let (id , b) = res . unwrap () ; (id , # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& b) . unwrap ()) }) } } else { parse_quote ! { map (| res | { # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& res . unwrap ()) . unwrap () }) } } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn send_bincode < N2 : Location , CoreType > (self , other : & N2 ,) -> Stream < 'a , N :: Out < CoreType > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T > , CoreType : Serialize + DeserializeOwned , { let serialize_pipeline = Some (serialize_bincode :: < CoreType > (N :: is_demux ())) ; let deserialize_pipeline = Some (deserialize_bincode :: < CoreType > (N :: is_tagged ())) ; Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bytes < N2 : Location > (self , other : & N2 ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T > , { Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline : None , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline : if N :: is_tagged () { Some (parse_quote ! (map (| (id , b) | (id , b . unwrap () . freeze ())))) } else { Some (parse_quote ! (map (| b | b . unwrap () . freeze ()))) } , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bincode_interleaved < N2 : Location , Tag , CoreType > (self , other : & N2 ,) -> Stream < 'a , CoreType , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T , Out < CoreType > = (Tag , CoreType) > , CoreType : Serialize + DeserializeOwned , { self . send_bincode :: < N2 , CoreType > (other) . map (q ! (| (_ , b) | b)) } pub fn send_bytes_interleaved < N2 : Location , Tag > (self , other : & N2 ,) -> Stream < 'a , Bytes , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T , Out < Bytes > = (Tag , Bytes) > , { self . send_bytes :: < N2 > (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bincode < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < T > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) > , T : Clone + Serialize + DeserializeOwned , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bincode (other) } pub fn broadcast_bincode_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , T , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) , Out < T > = (Tag , T) > + 'a , T : Clone + Serialize + DeserializeOwned , { self . broadcast_bincode (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bytes < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) > + 'a , T : Clone , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bytes (other) } pub fn broadcast_bytes_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , Bytes , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) , Out < Bytes > = (Tag , Bytes) > + 'a , T : Clone , { self . broadcast_bytes (other) . map (q ! (| (_ , b) | b)) } } } pub use stream :: { Bounded , NoTick , Stream , Tick , Unbounded } ; pub mod singleton { pub use std :: cell :: RefCell ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use crate :: builder :: FlowLeaves ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial , CycleComplete } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: Stream ; pub use crate :: singleton :: CrossResult ; # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Singleton < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Singleton :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } pub use crate :: singleton :: Singleton ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Singleton { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleComplete < 'a > for Singleton < 'a , T , Bounded , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleCollectionWithInitial < 'a > for Singleton < 'a , T , Bounded , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , initial : Self , l : LocationId ,) -> Self { Singleton :: new (l , ir_leaves , HfPlusNode :: Union (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , }) , initial . ir_node . into_inner () . into () ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Singleton < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Singleton { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , U , W , C , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (Self :: other_ir_node (other)) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Singleton < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CrossSingleton (Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , Box :: new (HfPlusNode :: Unpersist (Box :: new (Self :: other_ir_node (other)))) ,))) ,) } } pub use crate :: singleton :: Optional ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Optional { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } pub fn some (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: new (singleton . location_kind , singleton . ir_leaves , singleton . ir_node . into_inner () ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > From < Singleton < 'a , T , W , C , N > > for Optional < 'a , T , W , C , N > { fn from (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: some (singleton) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Optional < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Optional { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn into_stream (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , Tick , N > > ,) -> Optional < 'a , (T , O) , Bounded , Tick , N > where O : Clone , { let other : Optional < 'a , O , Bounded , Tick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn union (self , other : Optional < 'a , T , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Optional < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_samples (self) -> Stream < 'a , T , Unbounded , NoTick , N > { self . latest_tick () . all_ticks () } pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . latest_tick () . continue_if (samples . first ()) . latest () . tick_samples () } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Unbounded , NoTick , N > > ,) -> Optional < 'a , (T , O) , Unbounded , NoTick , N > where O : Clone , { let other : Optional < 'a , O , Unbounded , NoTick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } self . latest_tick () . cross_singleton (other . latest_tick ()) . latest () } } } pub use singleton :: { Optional , Singleton } ; pub mod location { pub use std :: marker :: PhantomData ; pub use crate :: location :: LocationId ; pub use crate :: location :: Location ; pub use crate :: location :: Process ; # [cfg (stageleft_macro)] impl < P > Clone for Process < P > { fn clone (& self) -> Self { Process { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < P > Location for Process < P > { fn id (& self) -> LocationId { LocationId :: Process (self . id) } } pub use crate :: location :: Cluster ; # [cfg (stageleft_macro)] impl < C > Clone for Cluster < C > { fn clone (& self) -> Self { Cluster { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < C > Location for Cluster < C > { fn id (& self) -> LocationId { LocationId :: Cluster (self . id) } } pub use crate :: location :: CanSend ; # [cfg (stageleft_macro)] impl < P1 , P2 > CanSend < Process < P2 > > for Process < P1 > { type In < T > = T ; type Out < T > = T ; fn is_demux () -> bool { false } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < P1 , C2 > CanSend < Cluster < C2 > > for Process < P1 > { type In < T > = (u32 , T) ; type Out < T > = T ; fn is_demux () -> bool { true } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < C1 , P2 > CanSend < Process < P2 > > for Cluster < C1 > { type In < T > = T ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { false } fn is_tagged () -> bool { true } } # [cfg (stageleft_macro)] impl < C1 , C2 > CanSend < Cluster < C2 > > for Cluster < C1 > { type In < T > = (u32 , T) ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { true } fn is_tagged () -> bool { true } } } pub use location :: { Cluster , Process } ; pub mod deploy { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use stageleft :: Quoted ; pub mod graphs { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use super :: { LocalDeploy , Node , ProcessSpec } ; pub use crate :: deploy :: graphs :: SingleProcessGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for SingleProcessGraph { type Process = SingleNode ; type Cluster = SingleNode ; type Meta = () ; type GraphId = () ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { SingleNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { SingleNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , SingleProcessGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> SingleNode { SingleNode { } } } pub use crate :: deploy :: graphs :: SingleNode ; # [cfg (stageleft_macro)] impl Node for SingleNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } pub use crate :: deploy :: graphs :: MultiGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for MultiGraph { type Process = MultiNode ; type Cluster = MultiNode ; type Meta = () ; type GraphId = usize ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { MultiNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { MultiNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , MultiGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> MultiNode { MultiNode { } } } pub use crate :: deploy :: graphs :: MultiNode ; # [cfg (stageleft_macro)] impl Node for MultiNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } } pub use graphs :: * ; pub use crate :: deploy :: LocalDeploy ; pub use crate :: deploy :: Deploy ; # [cfg (stageleft_macro)] impl < 'a , T : Deploy < 'a , Process = N , Cluster = C , Meta = M , GraphId = R > , N : Node < Meta = M > , C : Node < Meta = M > , M : Default , R , > LocalDeploy < 'a > for T { type Process = N ; type Cluster = C ; type Meta = M ; type GraphId = R ; fn has_trivial_node () -> bool { < T as Deploy < 'a > > :: has_trivial_node () } fn trivial_process (id : usize) -> Self :: Process { < T as Deploy < 'a > > :: trivial_process (id) } fn trivial_cluster (id : usize) -> Self :: Cluster { < T as Deploy < 'a > > :: trivail_cluster (id) } } pub use crate :: deploy :: ProcessSpec ; pub use crate :: deploy :: ClusterSpec ; pub use crate :: deploy :: Node ; } pub use deploy :: { ClusterSpec , Deploy , ProcessSpec } ; pub mod cycle { pub use std :: marker :: PhantomData ; pub use crate :: builder :: FlowLeaves ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: cycle :: CycleComplete ; pub use crate :: cycle :: CycleCollection ; pub use crate :: cycle :: CycleCollectionWithInitial ; pub use crate :: cycle :: HfCycle ; # [cfg (stageleft_macro)] impl < 'a , S : CycleComplete < 'a > > HfCycle < 'a , S > { pub fn complete (self , stream : S) { let ident = self . ident ; S :: complete (stream , ident) } } } pub use cycle :: HfCycle ; pub mod builder { pub use std :: cell :: RefCell ; pub use std :: collections :: HashMap ; pub use std :: marker :: PhantomData ; pub use std :: rc :: Rc ; pub use std :: time :: Duration ; pub use hydroflow :: futures :: stream :: Stream as FuturesStream ; pub use hydroflow :: { tokio , tokio_stream } ; pub use internal :: TokenStream ; pub use proc_macro2 :: Span ; pub use quote :: quote ; pub use runtime_support :: FreeVariable ; pub use stageleft :: * ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Cluster , Location , LocationId , Process } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: { HfCycle , Optional , RuntimeContext , Singleton , Stream } ; pub mod built { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use hydroflow_lang :: graph :: { eliminate_extra_unions_tees , HydroflowGraph } ; pub use super :: deploy :: { DeployFlow , DeployResult } ; pub use crate :: deploy :: { ClusterSpec , Deploy , LocalDeploy , ProcessSpec } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Cluster , Process } ; pub use crate :: HfCompiled ; pub use crate :: builder :: built :: BuiltFlow ; # [cfg (stageleft_macro)] impl < 'a > Drop for BuiltFlow < 'a > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped BuiltFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn ir (& self) -> & Vec < HfPlusLeaf < 'a > > { & self . ir } pub fn optimize_with (mut self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> BuiltFlow < 'a > { self . used = true ; BuiltFlow { ir : f (std :: mem :: take (& mut self . ir)) , processes : std :: mem :: take (& mut self . processes) , clusters : std :: mem :: take (& mut self . clusters) , used : false , _phantom : PhantomData , } } } pub fn build_inner (ir : & mut Vec < HfPlusLeaf >) -> BTreeMap < usize , HydroflowGraph > { let mut builders = BTreeMap :: new () ; let mut built_tees = HashMap :: new () ; let mut next_stmt_id = 0 ; for leaf in ir { leaf . emit (& mut builders , & mut built_tees , & mut next_stmt_id) ; } builders . into_iter () . map (| (k , v) | { let (mut flat_graph , _ , _) = v . build () ; eliminate_extra_unions_tees (& mut flat_graph) ; (k , flat_graph) }) . collect () } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn compile_no_network < D : LocalDeploy < 'a > > (mut self) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; HfCompiled { hydroflow_ir : build_inner (& mut self . ir) , extra_stmts : BTreeMap :: new () , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> BuiltFlow < 'a > { self . optimize_with (crate :: persist_pullup :: persist_pullup) } fn into_deploy < D : LocalDeploy < 'a > > (mut self) -> DeployFlow < 'a , D > { self . used = true ; let processes = if D :: has_trivial_node () { self . processes . iter () . map (| id | (* id , D :: trivial_process (* id))) . collect () } else { HashMap :: new () } ; let clusters = if D :: has_trivial_node () { self . clusters . iter () . map (| id | (* id , D :: trivial_cluster (* id))) . collect () } else { HashMap :: new () } ; DeployFlow { ir : std :: mem :: take (& mut self . ir) , nodes : processes , clusters , used : false , _phantom : PhantomData , } } pub fn with_process < P , D : LocalDeploy < 'a > > (self , process : & Process < P > , spec : impl ProcessSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_process (process , spec) } pub fn with_cluster < C , D : LocalDeploy < 'a > > (self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_cluster (cluster , spec) } pub fn compile < D : Deploy < 'a > + 'a > (self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . into_deploy :: < D > () . compile (env) } pub fn deploy < D : Deploy < 'a , CompileEnv = () > + 'a > (self , env : & mut D :: InstantiateEnv ,) -> DeployResult < 'a , D > { self . into_deploy :: < D > () . deploy (env) } } } pub mod deploy { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use proc_macro2 :: Span ; pub use stageleft :: Quoted ; pub use super :: built :: build_inner ; pub use crate :: deploy :: { LocalDeploy , Node } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: { Cluster , ClusterSpec , Deploy , HfCompiled , Process , ProcessSpec } ; pub use crate :: builder :: deploy :: DeployFlow ; # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > Drop for DeployFlow < 'a , D > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped DeployFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > DeployFlow < 'a , D > { pub fn with_process < P > (mut self , process : & Process < P > , spec : impl ProcessSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < P > () . to_string () ; self . nodes . insert (process . id , spec . build (process . id , & tag_name)) ; self } pub fn with_cluster < C > (mut self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < C > () . to_string () ; self . clusters . insert (cluster . id , spec . build (cluster . id , & tag_name)) ; self } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployFlow < 'a , D > { pub fn compile (mut self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; let mut seen_tees : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | leaf . compile_network :: < D > (env , & mut seen_tees , & self . nodes , & self . clusters)) . collect () ; let extra_stmts = self . extra_stmts (env) ; HfCompiled { hydroflow_ir : build_inner (& mut ir_leaves_networked) , extra_stmts , _phantom : PhantomData , } } fn extra_stmts (& self , env : & < D as Deploy < 'a > > :: CompileEnv) -> BTreeMap < usize , Vec < syn :: Stmt > > { let all_locations_count = self . nodes . len () + self . clusters . len () ; let mut extra_stmts : BTreeMap < usize , Vec < syn :: Stmt > > = BTreeMap :: new () ; for & c_id in self . clusters . keys () { let self_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , c_id) , Span :: call_site () ,) ; let self_id_expr = D :: cluster_self_id (env) . splice () ; extra_stmts . entry (c_id) . or_default () . push (syn :: parse_quote ! { let # self_id_ident = # self_id_expr ; }) ; for other_location in 0 .. all_locations_count { let other_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , c_id) , Span :: call_site () ,) ; let other_id_expr = D :: cluster_ids (env , c_id) . splice () ; extra_stmts . entry (other_location) . or_default () . push (syn :: parse_quote ! { let # other_id_ident = # other_id_expr ; }) ; } } extra_stmts } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a , CompileEnv = () > > DeployFlow < 'a , D > { # [must_use] pub fn deploy (mut self , env : & mut D :: InstantiateEnv) -> DeployResult < 'a , D > { self . used = true ; let mut seen_tees_instantiate : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | { leaf . compile_network :: < D > (& () , & mut seen_tees_instantiate , & self . nodes , & self . clusters ,) }) . collect () ; let mut compiled = build_inner (& mut ir_leaves_networked) ; let mut extra_stmts = self . extra_stmts (& ()) ; let mut meta = D :: Meta :: default () ; let (mut processes , mut clusters) = (std :: mem :: take (& mut self . nodes) . into_iter () . map (| (node_id , node) | { node . instantiate (env , & mut meta , compiled . remove (& node_id) . unwrap () , extra_stmts . remove (& node_id) . unwrap_or_default () ,) ; (node_id , node) }) . collect :: < HashMap < _ , _ > > () , std :: mem :: take (& mut self . clusters) . into_iter () . map (| (cluster_id , cluster) | { cluster . instantiate (env , & mut meta , compiled . remove (& cluster_id) . unwrap () , extra_stmts . remove (& cluster_id) . unwrap_or_default () ,) ; (cluster_id , cluster) }) . collect :: < HashMap < _ , _ > > () ,) ; for node in processes . values_mut () { node . update_meta (& meta) ; } for cluster in clusters . values_mut () { cluster . update_meta (& meta) ; } let mut seen_tees_connect = HashMap :: new () ; for leaf in ir_leaves_networked { leaf . connect_network (& mut seen_tees_connect) ; } DeployResult { processes , clusters , } } } pub use crate :: builder :: deploy :: DeployResult ; # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployResult < 'a , D > { pub fn get_process < P > (& self , p : & Process < P >) -> & D :: Process { let id = match p . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . processes . get (& id) . unwrap () } pub fn get_cluster < C > (& self , c : & Cluster < C >) -> & D :: Cluster { let id = match c . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . clusters . get (& id) . unwrap () } } } # [doc = " Tracks the leaves of the dataflow IR. This is referenced by"] # [doc = " `Stream` and `HfCycle` to build the IR. The inner option will"] # [doc = " be set to `None` when this builder is finalized."] pub type FlowLeaves < 'a > = Rc < RefCell < Option < Vec < HfPlusLeaf < 'a > > > > > ; pub use crate :: builder :: ClusterIds ; # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Vec < u32 > > for ClusterIds < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , & 'a Vec < u32 > > for ClusterIds < 'a > { } # [derive (Copy , Clone)] pub struct ClusterSelfId < 'a > { pub id : usize , pub _phantom : PhantomData < & 'a mut & 'a u32 > , } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < u32 > for ClusterSelfId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , u32 > for ClusterSelfId < 'a > { } pub use crate :: builder :: FlowBuilder ; # [cfg (stageleft_macro)] impl < 'a > Drop for FlowBuilder < 'a > { fn drop (& mut self) { if ! self . finalized { panic ! ("Dropped FlowBuilder without finalizing, you may have forgotten to call `with_default_optimize`, `optimize_with`, or `finalize`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > QuotedContext for FlowBuilder < 'a > { fn create () -> Self { FlowBuilder :: new () } } # [cfg (stageleft_macro)] impl < 'a > FlowBuilder < 'a > { # [allow (clippy :: new_without_default)] pub fn new () -> FlowBuilder < 'a > { FlowBuilder { ir_leaves : Rc :: new (RefCell :: new (Some (Vec :: new ()))) , nodes : RefCell :: new (vec ! []) , clusters : RefCell :: new (vec ! []) , cycle_ids : RefCell :: new (HashMap :: new ()) , next_node_id : RefCell :: new (0) , finalized : false , _phantom : PhantomData , } } pub fn finalize (mut self) -> built :: BuiltFlow < 'a > { self . finalized = true ; built :: BuiltFlow { ir : self . ir_leaves . borrow_mut () . take () . unwrap () , processes : self . nodes . replace (vec ! []) , clusters : self . clusters . replace (vec ! []) , used : false , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> built :: BuiltFlow < 'a > { self . finalize () . with_default_optimize () } pub fn optimize_with (self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> built :: BuiltFlow < 'a > { self . finalize () . optimize_with (f) } pub fn ir_leaves (& self) -> & FlowLeaves < 'a > { & self . ir_leaves } pub fn process < P > (& self) -> Process < P > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . nodes . borrow_mut () . push (id) ; Process { id , _phantom : PhantomData , } } pub fn cluster < C > (& self) -> Cluster < C > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . clusters . borrow_mut () . push (id) ; Cluster { id , _phantom : PhantomData , } } pub fn runtime_context (& self) -> RuntimeContext < 'a > { RuntimeContext { _phantom : PhantomData , } } pub fn cluster_members < C > (& self , cluster : & Cluster < C > ,) -> impl Quoted < 'a , & 'a Vec < u32 > > + Copy + 'a { ClusterIds { id : cluster . id , _phantom : PhantomData , } } pub fn cluster_self_id < C > (& self , cluster : & Cluster < C >) -> impl Quoted < 'a , u32 > + Copy + 'a { ClusterSelfId { id : cluster . id , _phantom : PhantomData , } } pub fn spin < L : Location > (& self , on : & L) -> Stream < 'a , () , Unbounded , NoTick , L > { Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Spin () , location_kind : on . id () , })) ,) } pub fn spin_batch < L : Location > (& self , on : & L , batch_size : impl Quoted < 'a , usize > + Copy + 'a ,) -> Stream < 'a , () , Bounded , Tick , L > { self . spin (on) . flat_map (q ! (move | _ | 0 .. batch_size)) . map (q ! (| _ | ())) . tick_batch () } pub fn source_stream < T , E : FuturesStream < Item = T > + Unpin , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Unbounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Stream (e . into ()) , location_kind : on . id () , })) ,) } pub fn source_iter < T , E : IntoIterator < Item = T > , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Bounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , })) ,) } pub fn singleton < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Singleton < 'a , T , Bounded , NoTick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Singleton :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,)))) ,) } pub fn singleton_first_tick < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Optional < 'a , T , Bounded , Tick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,) } pub fn source_interval < L : Location > (& self , on : & L , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , () , Unbounded , NoTick , L > { let interval = interval . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : on . id () , })) ,) } pub fn source_interval_delayed < L : Location > (& self , on : & L , delay : impl Quoted < 'a , Duration > + Copy + 'a , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , tokio :: time :: Instant , Unbounded , NoTick , L > { self . source_stream (on , q ! (tokio_stream :: wrappers :: IntervalStream :: new (tokio :: time :: interval_at (tokio :: time :: Instant :: now () + delay , interval))) ,) . tick_batch () . first () . latest () } pub fn cycle < S : CycleCollection < 'a > > (& self , on : & S :: Location) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , on . id ()) ,) } pub fn cycle_with_initial < S : CycleCollectionWithInitial < 'a > > (& self , on : & S :: Location , initial : S ,) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , initial , on . id ()) ,) } } } pub use builder :: FlowBuilder ; pub mod ir { pub use core :: panic ; pub use std :: cell :: RefCell ; pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow_lang :: graph :: FlatGraphBuilder ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: ToTokens ; pub use syn :: parse_quote ; pub use crate :: deploy :: Deploy ; pub use crate :: location :: LocationId ; pub use crate :: ir :: DebugExpr ; # [cfg (stageleft_macro)] impl From < syn :: Expr > for DebugExpr { fn from (expr : syn :: Expr) -> DebugExpr { DebugExpr (expr) } } # [cfg (stageleft_macro)] impl Deref for DebugExpr { type Target = syn :: Expr ; fn deref (& self) -> & Self :: Target { & self . 0 } } # [cfg (stageleft_macro)] impl ToTokens for DebugExpr { fn to_tokens (& self , tokens : & mut TokenStream) { self . 0 . to_tokens (tokens) ; } } # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugExpr { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "{}" , self . 0 . to_token_stream ()) } } pub use crate :: ir :: DebugInstantiate ; # [cfg (stageleft_macro)] impl < 'a > std :: fmt :: Debug for DebugInstantiate < 'a > { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<network instantiate>") } } pub use crate :: ir :: DebugPipelineFn ; # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugPipelineFn { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<function>") } } pub use crate :: ir :: HfPlusSource ; pub use crate :: ir :: HfPlusLeaf ; # [cfg (stageleft_macro)] impl < 'a > HfPlusLeaf < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . compile_network :: < D > (compile_env , s , nodes , clusters) ; } , seen_tees ,) } pub fn connect_network (self , seen_tees : & mut SeenTees < 'a >) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . connect_network (s) ; } , seen_tees ,) } pub fn transform_children (self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) -> HfPlusLeaf < 'a > { match self { HfPlusLeaf :: ForEach { f , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: ForEach { f , input } } HfPlusLeaf :: DestSink { sink , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: DestSink { sink , input } } HfPlusLeaf :: CycleSink { ident , location_kind , mut input , } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: CycleSink { ident , location_kind , input , } } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) { match self { HfPlusLeaf :: ForEach { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> for_each (# f) ; }) ; } HfPlusLeaf :: DestSink { sink , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink) ; }) ; } HfPlusLeaf :: CycleSink { ident , location_kind , input , } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; assert_eq ! (input_location_id , * location_id , "cycle_sink location mismatch") ; graph_builders . entry (* location_id) . or_default () . add_statement (parse_quote ! { # ident = # input_ident ; }) ; } } } } pub use crate :: ir :: HfPlusNode ; pub type SeenTees < 'a > = HashMap < * const RefCell < HfPlusNode < 'a > > , Rc < RefCell < HfPlusNode < 'a > > > > ; # [cfg (stageleft_macro)] impl < 'a > HfPlusNode < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (& mut self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) { self . transform_children (| n , s | n . compile_network :: < D > (compile_env , s , nodes , clusters) , seen_tees ,) ; if let HfPlusNode :: Network { from_location , to_location , instantiate_fn , .. } = self { let (sink_expr , source_expr , connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { let ((sink , source) , connect_fn) = match (from_location , to_location) { (LocationId :: Process (from) , LocationId :: Process (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: o2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Process (from) , LocationId :: Cluster (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: o2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Process (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: m2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Cluster (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: m2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } } ; (sink , source , connect_fn) } DebugInstantiate :: Finalized (_ , _ , _) => panic ! ("network already finalized") , } ; * instantiate_fn = DebugInstantiate :: Finalized (sink_expr , source_expr , connect_fn) ; } } pub fn connect_network (& mut self , seen_tees : & mut SeenTees < 'a >) { self . transform_children (| n , s | n . connect_network (s) , seen_tees) ; if let HfPlusNode :: Network { instantiate_fn , .. } = self { match instantiate_fn { DebugInstantiate :: Building () => panic ! ("network not built") , DebugInstantiate :: Finalized (_ , _ , ref connect_fn) => { connect_fn () ; } } } } pub fn transform_children (& mut self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) { match self { HfPlusNode :: Placeholder => { panic ! () ; } HfPlusNode :: Source { .. } => { } HfPlusNode :: CycleSource { .. } => { } HfPlusNode :: Tee { inner } => { if let Some (transformed) = seen_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { * inner = transformed . clone () ; } else { let transformed_cell = Rc :: new (RefCell :: new (HfPlusNode :: Placeholder)) ; seen_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , transformed_cell . clone () ,) ; let mut orig = inner . replace (HfPlusNode :: Placeholder) ; transform (& mut orig , seen_tees) ; * transformed_cell . borrow_mut () = orig ; * inner = transformed_cell ; } } HfPlusNode :: Persist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Unpersist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Delta (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Union (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossProduct (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossSingleton (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Join (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Difference (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: AntiJoin (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Map { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FlatMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Filter { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FilterMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Sort (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: DeferTick (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Enumerate (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Inspect { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Unique (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Fold { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FoldKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Reduce { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: ReduceKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Network { input , .. } => { transform (input . as_mut () , seen_tees) ; } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) -> (syn :: Ident , usize) { match self { HfPlusNode :: Placeholder => { panic ! () } HfPlusNode :: Persist (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let persist_id = * next_stmt_id ; * next_stmt_id += 1 ; let persist_ident = syn :: Ident :: new (& format ! ("stream_{}" , persist_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # persist_ident = # inner_ident -> persist ::<'static > () ; }) ; (persist_ident , location) } HfPlusNode :: Unpersist (_) => { panic ! ("Unpersist is a marker node and should have been optimized away. This is likely a compiler bug.") } HfPlusNode :: Delta (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let delta_id = * next_stmt_id ; * next_stmt_id += 1 ; let delta_ident = syn :: Ident :: new (& format ! ("stream_{}" , delta_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # delta_ident = # inner_ident -> multiset_delta () ; }) ; (delta_ident , location) } HfPlusNode :: Source { source , location_kind , } => { let source_id = * next_stmt_id ; * next_stmt_id += 1 ; let source_ident = syn :: Ident :: new (& format ! ("stream_{}" , source_id) , Span :: call_site ()) ; let source_stmt = match source { HfPlusSource :: Stream (expr) => { parse_quote ! { # source_ident = source_stream (# expr) ; } } HfPlusSource :: Iter (expr) => { parse_quote ! { # source_ident = source_iter (# expr) ; } } HfPlusSource :: Interval (expr) => { parse_quote ! { # source_ident = source_interval (# expr) ; } } HfPlusSource :: Spin () => { parse_quote ! { # source_ident = spin () ; } } } ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; graph_builders . entry (* location_id) . or_default () . add_statement (source_stmt) ; (source_ident , * location_id) } HfPlusNode :: CycleSource { ident , location_kind , } => { let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; (ident . clone () , * location_id) } HfPlusNode :: Tee { inner } => { if let Some (ret) = built_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { ret . clone () } else { let (inner_ident , inner_location_id) = inner . borrow () . emit (graph_builders , built_tees , next_stmt_id) ; let tee_id = * next_stmt_id ; * next_stmt_id += 1 ; let tee_ident = syn :: Ident :: new (& format ! ("stream_{}" , tee_id) , Span :: call_site ()) ; let builder = graph_builders . entry (inner_location_id) . or_default () ; builder . add_statement (parse_quote ! { # tee_ident = # inner_ident -> tee () ; }) ; built_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , (tee_ident . clone () , inner_location_id) ,) ; (tee_ident , inner_location_id) } } HfPlusNode :: Union (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "union inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let union_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # union_ident = union () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [0] # union_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # union_ident ; }) ; (union_ident , left_location_id) } HfPlusNode :: CrossSingleton (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "cross_singleton inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let cross_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # cross_ident = cross_singleton () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [input] # cross_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [single] # cross_ident ; }) ; (cross_ident , left_location_id) } HfPlusNode :: CrossProduct (..) | HfPlusNode :: Join (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: CrossProduct (..)) { parse_quote ! (cross_join_multiset) } else { parse_quote ! (join_multiset) } ; let (HfPlusNode :: CrossProduct (left , right) | HfPlusNode :: Join (left , right)) = self else { unreachable ! () } ; let (left_inner , left_was_persist) = if let HfPlusNode :: Persist (left) = left . as_ref () { (left , true) } else { (left , false) } ; let (right_inner , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left_inner . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right_inner . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "join / cross product inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; match (left_was_persist , right_was_persist) { (true , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'static > () ; }) ; } (true , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'tick > () ; }) ; } (false , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } (false , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } } ; builder . add_statement (parse_quote ! { # left_ident -> [0] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Difference (..) | HfPlusNode :: AntiJoin (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Difference (..)) { parse_quote ! (difference_multiset) } else { parse_quote ! (anti_join_multiset) } ; let (HfPlusNode :: Difference (left , right) | HfPlusNode :: AntiJoin (left , right)) = self else { unreachable ! () } ; let (right , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "difference / anti join inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; if right_was_persist { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } else { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } builder . add_statement (parse_quote ! { # left_ident -> [pos] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [neg] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Map { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let map_id = * next_stmt_id ; * next_stmt_id += 1 ; let map_ident = syn :: Ident :: new (& format ! ("stream_{}" , map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # map_ident = # input_ident -> map (# f) ; }) ; (map_ident , input_location_id) } HfPlusNode :: FlatMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let flat_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let flat_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , flat_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # flat_map_ident = # input_ident -> flat_map (# f) ; }) ; (flat_map_ident , input_location_id) } HfPlusNode :: Filter { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_ident = # input_ident -> filter (# f) ; }) ; (filter_ident , input_location_id) } HfPlusNode :: FilterMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_map_ident = # input_ident -> filter_map (# f) ; }) ; (filter_map_ident , input_location_id) } HfPlusNode :: Sort (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sort_id = * next_stmt_id ; * next_stmt_id += 1 ; let sort_ident = syn :: Ident :: new (& format ! ("stream_{}" , sort_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # sort_ident = # input_ident -> sort () ; }) ; (sort_ident , input_location_id) } HfPlusNode :: DeferTick (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let defer_tick_id = * next_stmt_id ; * next_stmt_id += 1 ; let defer_tick_ident = syn :: Ident :: new (& format ! ("stream_{}" , defer_tick_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # defer_tick_ident = # input_ident -> defer_tick_lazy () ; }) ; (defer_tick_ident , input_location_id) } HfPlusNode :: Enumerate (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let enumerate_id = * next_stmt_id ; * next_stmt_id += 1 ; let enumerate_ident = syn :: Ident :: new (& format ! ("stream_{}" , enumerate_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # enumerate_ident = # input_ident -> enumerate () ; }) ; (enumerate_ident , input_location_id) } HfPlusNode :: Inspect { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let inspect_id = * next_stmt_id ; * next_stmt_id += 1 ; let inspect_ident = syn :: Ident :: new (& format ! ("stream_{}" , inspect_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # inspect_ident = # input_ident -> inspect (# f) ; }) ; (inspect_ident , input_location_id) } HfPlusNode :: Unique (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let unique_id = * next_stmt_id ; * next_stmt_id += 1 ; let unique_ident = syn :: Ident :: new (& format ! ("stream_{}" , unique_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # unique_ident = # input_ident -> unique ::<'tick > () ; }) ; (unique_ident , input_location_id) } HfPlusNode :: Fold { .. } | HfPlusNode :: FoldKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Fold { .. }) { parse_quote ! (fold) } else { parse_quote ! (fold_keyed) } ; let (HfPlusNode :: Fold { init , acc , input } | HfPlusNode :: FoldKeyed { init , acc , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let fold_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'static > (# init , # acc) ; }) ; } else { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'tick > (# init , # acc) ; }) ; } (fold_ident , input_location_id) } HfPlusNode :: Reduce { .. } | HfPlusNode :: ReduceKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Reduce { .. }) { parse_quote ! (reduce) } else { parse_quote ! (reduce_keyed) } ; let (HfPlusNode :: Reduce { f , input } | HfPlusNode :: ReduceKeyed { f , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let reduce_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'static > (# f) ; }) ; } else { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'tick > (# f) ; }) ; } (reduce_ident , input_location_id) } HfPlusNode :: Network { from_location : _ , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input , } => { let (sink_expr , source_expr , _connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { panic ! ("Expected the network to be finalized") } DebugInstantiate :: Finalized (sink , source , connect_fn) => { (sink , source , connect_fn) } } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sender_builder = graph_builders . entry (input_location_id) . or_default () ; if let Some (serialize_pipeline) = serialize_pipeline { sender_builder . add_statement (parse_quote ! { # input_ident -> # serialize_pipeline -> dest_sink (# sink_expr) ; }) ; } else { sender_builder . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink_expr) ; }) ; } let to_id = match to_location { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let receiver_builder = graph_builders . entry (* to_id) . or_default () ; let receiver_stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let receiver_stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , receiver_stream_id) , Span :: call_site ()) ; if let Some (deserialize_pipeline) = deserialize_pipeline { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) -> # deserialize_pipeline ; }) ; } else { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) ; }) ; } (receiver_stream_ident , * to_id) } } } } } pub mod persist_pullup { pub use std :: cell :: RefCell ; pub use std :: collections :: HashSet ; pub use std :: ops :: Deref ; pub use crate :: ir :: * ; pub fn persist_pullup_node < 'a > (node : & mut HfPlusNode < 'a > , seen_tees : & mut SeenTees < 'a > , persist_pulled_tees : & mut HashSet < * const RefCell < HfPlusNode < 'a > > > ,) { node . transform_children (| n , s | persist_pullup_node (n , s , persist_pulled_tees) , seen_tees ,) ; match node { HfPlusNode :: Unpersist (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Unpersist (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Delta (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Delta (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Tee { inner } => { if persist_pulled_tees . contains (& (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >)) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } else { let inner_borrow = inner . borrow () ; if let HfPlusNode :: Persist (_) = inner_borrow . deref () { drop (inner_borrow) ; persist_pulled_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >) ; if let HfPlusNode :: Persist (box behind_persist) = inner . replace (HfPlusNode :: Placeholder) { * inner . borrow_mut () = behind_persist ; } else { unreachable ! () } * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } } } HfPlusNode :: Map { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Map { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Map { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: FlatMap { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: FlatMap { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: FlatMap { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Filter { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Filter { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Filter { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Network { input : box HfPlusNode :: Persist (_) , .. } => { if let HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Union (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Union (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Union (left , right))) ; } else { unreachable ! () } } HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: CrossProduct (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,) ,)))) ; } else { unreachable ! () } } HfPlusNode :: Join (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Join (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: Join (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,))))) ; } else { unreachable ! () } } _ => { } } } pub fn persist_pullup (ir : Vec < HfPlusLeaf >) -> Vec < HfPlusLeaf > { let mut seen_tees = Default :: default () ; let mut persist_pulled_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| n , s | persist_pullup_node (n , s , & mut persist_pulled_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn persist_pullup_through_map () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } # [test] fn persist_pullup_behind_tee () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; let before_tee = flow . source_iter (& process , q ! (0 .. 10)) . tick_batch () . persist () ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } } } pub mod profiler { pub use std :: cell :: RefCell ; pub use hydroflow :: futures :: channel :: mpsc :: UnboundedSender ; pub use stageleft :: * ; pub use crate as hydroflow_plus ; pub use crate :: ir :: * ; pub use crate :: RuntimeContext ; pub fn increment_counter (count : & mut u64) { * count += 1 ; } pub fn quoted_any_fn < 'a , F : Fn (& usize) + 'a , Q : IntoQuotedMut < 'a , F > > (q : Q) -> Q { q } # [doc = " Add a profiling node before each node to count the cardinality of its input"] pub fn add_profiling_node < 'a > (node : & mut HfPlusNode < 'a > , _context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > , id : & mut u32 , seen_tees : & mut SeenTees < 'a > ,) { let my_id = * id ; * id += 1 ; node . transform_children (| node , seen_tees | { add_profiling_node (node , _context , counters , counter_queue , id , seen_tees) } , seen_tees ,) ; let orig_node = std :: mem :: replace (node , HfPlusNode :: Placeholder) ; * node = HfPlusNode :: Inspect { f : quoted_any_fn (q ! ({ counter_queue . borrow () . unbounded_send ((my_id as usize , counters . borrow () [my_id as usize])) . unwrap () ; counters . borrow_mut () [my_id as usize] = 0 ; move | _ | { hydroflow_plus :: profiler :: increment_counter (& mut counters . borrow_mut () [my_id as usize] ,) ; } })) . splice () . into () , input : Box :: new (orig_node) , } } # [doc = " Count the cardinality of each input and periodically output to a file"] pub fn profiling < 'a > (ir : Vec < HfPlusLeaf < 'a > > , context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > ,) -> Vec < HfPlusLeaf < 'a > > { let mut id = 0 ; let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | { add_profiling_node (node , context , counters , counter_queue , & mut id , seen_tees) } , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn profiler_wrapping_all_operators () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let runtime_context = flow . runtime_context () ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (& built . ir ()) ; let counters = RuntimeData :: new ("Fake") ; let counter_queue = RuntimeData :: new ("Fake") ; let pushed_down = built . with_default_optimize () . optimize_with (| ir | super :: profiling (ir , runtime_context , counters , counter_queue)) ; insta :: assert_debug_snapshot ! (& pushed_down . ir ()) ; let _ = pushed_down . compile_no_network :: < MultiGraph > () ; } } } pub mod properties { pub use std :: collections :: HashSet ; pub use stageleft :: * ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , SeenTees } ; pub use crate :: properties :: PropertyDatabase ; # [doc = " Allows us to convert the hydroflow datatype for folds to a binary operation for the algebra"] # [doc = " property tests."] # [allow (dead_code)] pub fn convert_hf_to_binary < I , A : Default , F : Fn (& mut A , I) > (f : F) -> impl Fn (I , I) -> A { move | a , b | { let mut acc = Default :: default () ; f (& mut acc , a) ; f (& mut acc , b) ; acc } } # [cfg (stageleft_macro)] impl PropertyDatabase { # [doc = " Tags the expression as commutative."] pub fn add_commutative_tag < 'a , I , A , F : Fn (& mut A , I) , Q : Quoted < 'a , F > + Clone > (& mut self , expr : Q ,) -> Q { let expr_clone = expr . clone () ; self . commutative . insert (expr_clone . splice ()) ; expr } pub fn is_tagged_commutative (& self , expr : & syn :: Expr) -> bool { self . commutative . contains (expr) } } pub fn properties_optimize_node < 'a > (node : & mut HfPlusNode < 'a > , db : & PropertyDatabase , seen_tees : & mut SeenTees < 'a > ,) { node . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , seen_tees ,) ; match node { HfPlusNode :: ReduceKeyed { f , .. } if db . is_tagged_commutative (& f . 0) => { dbg ! ("IDENTIFIED COMMUTATIVE OPTIMIZATION for {:?}" , & f) ; } _ => { } } } pub fn properties_optimize < 'a > (ir : Vec < HfPlusLeaf < 'a > > , db : & PropertyDatabase ,) -> Vec < HfPlusLeaf < 'a > > { let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use super :: * ; use crate :: deploy :: SingleProcessGraph ; use crate :: FlowBuilder ; # [test] fn test_property_database () { let mut db = PropertyDatabase :: default () ; assert ! (! db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; let _ = db . add_commutative_tag (q ! (| a : & mut i32 , b : i32 | * a += b)) ; assert ! (db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; } # [test] fn test_property_optimized () { let flow = FlowBuilder :: new () ; let mut database = PropertyDatabase :: default () ; let process = flow . process :: < () > () ; let counter_func = q ! (| count : & mut i32 , _ | * count += 1) ; let _ = database . add_commutative_tag (counter_func) ; flow . source_iter (& process , q ! (vec ! [])) . map (q ! (| string : String | (string , ()))) . tick_batch () . fold_keyed (q ! (|| 0) , counter_func) . all_ticks () . for_each (q ! (| (string , count) | println ! ("{}: {}" , string , count))) ; let built = flow . finalize () . optimize_with (| ir | properties_optimize (ir , & database)) . with_default_optimize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let _ = built . compile_no_network :: < SingleProcessGraph > () ; } } } pub use crate :: RuntimeContext ; # [cfg (stageleft_macro)] impl Copy for RuntimeContext < '_ > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Context > for RuntimeContext < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (quote ! (& context))) } } pub use crate :: HfCompiled ; # [cfg (stageleft_macro)] impl < 'a , ID > HfCompiled < 'a , ID > { pub fn hydroflow_ir (& self) -> & BTreeMap < usize , HydroflowGraph > { & self . hydroflow_ir } } # [cfg (stageleft_macro)] impl < 'a > HfCompiled < 'a , usize > { pub fn with_dynamic_id (self , id : impl Quoted < 'a , usize >) -> HfBuiltWithId < 'a > { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; let mut conditioned_tokens = None ; for (subgraph_id , flat_graph) in self . hydroflow_ir { let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; let my_extra_stmts = self . extra_stmts . get (& subgraph_id) . cloned () . unwrap_or_default () ; if let Some (conditioned_tokens) = conditioned_tokens . as_mut () { * conditioned_tokens = syn :: parse_quote ! { # conditioned_tokens else if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } } ; } else { conditioned_tokens = Some (syn :: parse_quote ! { if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } }) ; } } let conditioned_tokens : TokenStream = conditioned_tokens . unwrap () ; let id = id . splice () ; HfBuiltWithId { tokens : syn :: parse_quote ! ({ let __given_id = # id ; # conditioned_tokens else { panic ! ("Invalid node id: {}" , __given_id) ; } }) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfCompiled < 'a , () > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfCompiled < 'a , () > { fn to_tokens (mut self) -> (Option < TokenStream > , Option < TokenStream >) { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; if self . hydroflow_ir . len () != 1 { panic ! ("Expected exactly one subgraph in the Hydroflow IR") ; } let flat_graph = self . hydroflow_ir . remove (& 0) . unwrap () ; let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; (None , Some (tokens)) } } pub use crate :: HfBuiltWithId ; # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfBuiltWithId < 'a > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfBuiltWithId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (self . tokens)) } }
[INFO] [stdout] 1 + pub use std :: collections :: BTreeMap ; pub use std :: marker :: PhantomData ; pub use hydroflow :: scheduled :: context :: Context ; pub use hydroflow :: scheduled :: graph :: Hydroflow ; pub use hydroflow :: * ; pub use lang :: graph :: { partition_graph , HydroflowGraph } ; pub use proc_macro2 :: TokenStream ; pub use quote :: quote ; pub use stageleft :: runtime_support :: FreeVariable ; pub use stageleft :: Quoted ; pub mod runtime_support { pub use bincode ; } pub mod stream { pub use std :: cell :: RefCell ; pub use std :: hash :: Hash ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow :: bytes :: Bytes ; pub use hydroflow :: futures :: Sink ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: quote ; pub use serde :: de :: DeserializeOwned ; pub use serde :: Serialize ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use syn :: parse_quote ; pub use crate :: builder :: { ClusterIds , FlowLeaves } ; pub use crate :: cycle :: { CycleCollection , CycleComplete } ; pub use crate :: ir :: { DebugInstantiate , HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { CanSend , Location , LocationId } ; pub use crate :: { Cluster , Optional , Singleton } ; pub use crate :: stream :: Unbounded ; pub use crate :: stream :: Bounded ; pub use crate :: stream :: NoTick ; pub use crate :: stream :: Tick ; pub use crate :: stream :: Stream ; # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Stream { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Stream < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Stream { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , C , N > > ,) -> Stream < 'a , (T , O) , W , C , N > where O : Clone , { let other : Optional < 'a , O , Bounded , C , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn cross_product < O > (self , other : Stream < 'a , O , W , C , N >) -> Stream < 'a , (T , O) , W , C , N > where T : Clone , O : Clone , { if self . location_kind != other . location_kind { panic ! ("cross_product must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossProduct (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn union (self , other : Stream < 'a , T , W , C , N >) -> Stream < 'a , T , W , C , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn dest_sink < S : Unpin + Sink < T > + 'a > (self , sink : impl Quoted < 'a , S >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: DestSink { sink : sink . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn first (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } # [doc = " Allow this stream through if the other stream has elements, otherwise the output is empty."] pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } # [doc = " Allow this stream through if the other stream is empty, otherwise the output is empty."] pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn enumerate (self) -> Stream < 'a , (usize , T) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Enumerate (Box :: new (self . ir_node . into_inner ())) ,) } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn sort (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Ord , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Sort (Box :: new (self . ir_node . into_inner ())) ,) } pub fn count (self) -> Singleton < 'a , usize , Bounded , Tick , N > { self . fold (q ! (|| 0usize) , q ! (| count , _ | * count += 1)) } pub fn delta (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } pub fn unique (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Eq + Hash , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unique (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn tick_batch (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_prefix (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { self . tick_batch () . persist () } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn for_each < F : Fn (T) + 'a > (self , f : impl IntoQuotedMut < 'a , F >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: ForEach { input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , f : f . splice () . into () , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Unbounded , NoTick , N > { pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . tick_batch () . continue_if (samples . first ()) . all_ticks () } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Unbounded , NoTick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , C , N : Location > Stream < 'a , T , Bounded , C , N > { pub fn filter_not_in (self , other : Stream < 'a , T , Bounded , C , N >) -> Stream < 'a , T , Bounded , C , N > where T : Eq + Hash , { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Difference (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Stream < 'a , & T , W , C , N > { pub fn cloned (self) -> Stream < 'a , T , W , C , N > { self . map (q ! (| d | d . clone ())) } } # [cfg (stageleft_macro)] impl < 'a , K , V1 , W , C , N : Location > Stream < 'a , (K , V1) , W , C , N > { pub fn join < W2 , V2 > (self , n : Stream < 'a , (K , V2) , W2 , C , N > ,) -> Stream < 'a , (K , (V1 , V2)) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Join (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } pub fn anti_join < W2 > (self , n : Stream < 'a , K , W2 , C , N >) -> Stream < 'a , (K , V1) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("anti_join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: AntiJoin (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , K : Eq + Hash , V , N : Location > Stream < 'a , (K , V) , Bounded , Tick , N > { pub fn fold_keyed < A , I : Fn () -> A + 'a , F : Fn (& mut A , V) + 'a > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , A) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FoldKeyed { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce_keyed < F : Fn (& mut V , V) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , V) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: ReduceKeyed { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } pub fn get_this_crate () -> TokenStream { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , Span :: call_site ()) ; quote ! { # ident } } } } pub fn serialize_bincode < T : Serialize > (is_demux : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if is_demux { parse_quote ! { map (| (id , data) | { (id , # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into ()) }) } } else { parse_quote ! { map (| data | { # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into () }) } } } pub fn deserialize_bincode < T : DeserializeOwned > (tagged : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if tagged { parse_quote ! { map (| res | { let (id , b) = res . unwrap () ; (id , # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& b) . unwrap ()) }) } } else { parse_quote ! { map (| res | { # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& res . unwrap ()) . unwrap () }) } } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn send_bincode < N2 : Location , CoreType > (self , other : & N2 ,) -> Stream < 'a , N :: Out < CoreType > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T > , CoreType : Serialize + DeserializeOwned , { let serialize_pipeline = Some (serialize_bincode :: < CoreType > (N :: is_demux ())) ; let deserialize_pipeline = Some (deserialize_bincode :: < CoreType > (N :: is_tagged ())) ; Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bytes < N2 : Location > (self , other : & N2 ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T > , { Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline : None , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline : if N :: is_tagged () { Some (parse_quote ! (map (| (id , b) | (id , b . unwrap () . freeze ())))) } else { Some (parse_quote ! (map (| b | b . unwrap () . freeze ()))) } , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bincode_interleaved < N2 : Location , Tag , CoreType > (self , other : & N2 ,) -> Stream < 'a , CoreType , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T , Out < CoreType > = (Tag , CoreType) > , CoreType : Serialize + DeserializeOwned , { self . send_bincode :: < N2 , CoreType > (other) . map (q ! (| (_ , b) | b)) } pub fn send_bytes_interleaved < N2 : Location , Tag > (self , other : & N2 ,) -> Stream < 'a , Bytes , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T , Out < Bytes > = (Tag , Bytes) > , { self . send_bytes :: < N2 > (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bincode < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < T > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) > , T : Clone + Serialize + DeserializeOwned , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bincode (other) } pub fn broadcast_bincode_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , T , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) , Out < T > = (Tag , T) > + 'a , T : Clone + Serialize + DeserializeOwned , { self . broadcast_bincode (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bytes < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) > + 'a , T : Clone , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bytes (other) } pub fn broadcast_bytes_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , Bytes , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) , Out < Bytes > = (Tag , Bytes) > + 'a , T : Clone , { self . broadcast_bytes (other) . map (q ! (| (_ , b) | b)) } } } pub use stream :: { Bounded , NoTick , Stream , Tick , Unbounded } ; pub mod singleton { pub use std :: cell :: RefCell ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use crate :: builder :: FlowLeaves ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial , CycleComplete } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: Stream ; pub use crate :: singleton :: CrossResult ; # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Singleton < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Singleton :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } pub use crate :: singleton :: Singleton ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Singleton { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleComplete < 'a > for Singleton < 'a , T , Bounded , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleCollectionWithInitial < 'a > for Singleton < 'a , T , Bounded , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , initial : Self , l : LocationId ,) -> Self { Singleton :: new (l , ir_leaves , HfPlusNode :: Union (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , }) , initial . ir_node . into_inner () . into () ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Singleton < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Singleton { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , U , W , C , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (Self :: other_ir_node (other)) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Singleton < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CrossSingleton (Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , Box :: new (HfPlusNode :: Unpersist (Box :: new (Self :: other_ir_node (other)))) ,))) ,) } } pub use crate :: singleton :: Optional ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Optional { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } pub fn some (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: new (singleton . location_kind , singleton . ir_leaves , singleton . ir_node . into_inner () ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > From < Singleton < 'a , T , W , C , N > > for Optional < 'a , T , W , C , N > { fn from (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: some (singleton) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Optional < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Optional { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn into_stream (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , Tick , N > > ,) -> Optional < 'a , (T , O) , Bounded , Tick , N > where O : Clone , { let other : Optional < 'a , O , Bounded , Tick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn union (self , other : Optional < 'a , T , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Optional < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_samples (self) -> Stream < 'a , T , Unbounded , NoTick , N > { self . latest_tick () . all_ticks () } pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . latest_tick () . continue_if (samples . first ()) . latest () . tick_samples () } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Unbounded , NoTick , N > > ,) -> Optional < 'a , (T , O) , Unbounded , NoTick , N > where O : Clone , { let other : Optional < 'a , O , Unbounded , NoTick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } self . latest_tick () . cross_singleton (other . latest_tick ()) . latest () } } } pub use singleton :: { Optional , Singleton } ; pub mod location { pub use std :: marker :: PhantomData ; pub use crate :: location :: LocationId ; pub use crate :: location :: Location ; pub use crate :: location :: Process ; # [cfg (stageleft_macro)] impl < P > Clone for Process < P > { fn clone (& self) -> Self { Process { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < P > Location for Process < P > { fn id (& self) -> LocationId { LocationId :: Process (self . id) } } pub use crate :: location :: Cluster ; # [cfg (stageleft_macro)] impl < C > Clone for Cluster < C > { fn clone (& self) -> Self { Cluster { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < C > Location for Cluster < C > { fn id (& self) -> LocationId { LocationId :: Cluster (self . id) } } pub use crate :: location :: CanSend ; # [cfg (stageleft_macro)] impl < P1 , P2 > CanSend < Process < P2 > > for Process < P1 > { type In < T > = T ; type Out < T > = T ; fn is_demux () -> bool { false } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < P1 , C2 > CanSend < Cluster < C2 > > for Process < P1 > { type In < T > = (u32 , T) ; type Out < T > = T ; fn is_demux () -> bool { true } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < C1 , P2 > CanSend < Process < P2 > > for Cluster < C1 > { type In < T > = T ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { false } fn is_tagged () -> bool { true } } # [cfg (stageleft_macro)] impl < C1 , C2 > CanSend < Cluster < C2 > > for Cluster < C1 > { type In < T > = (u32 , T) ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { true } fn is_tagged () -> bool { true } } } pub use location :: { Cluster , Process } ; pub mod deploy { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use stageleft :: Quoted ; pub mod graphs { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use super :: { LocalDeploy , Node , ProcessSpec } ; pub use crate :: deploy :: graphs :: SingleProcessGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for SingleProcessGraph { type Process = SingleNode ; type Cluster = SingleNode ; type Meta = () ; type GraphId = () ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { SingleNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { SingleNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , SingleProcessGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> SingleNode { SingleNode { } } } pub use crate :: deploy :: graphs :: SingleNode ; # [cfg (stageleft_macro)] impl Node for SingleNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } pub use crate :: deploy :: graphs :: MultiGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for MultiGraph { type Process = MultiNode ; type Cluster = MultiNode ; type Meta = () ; type GraphId = usize ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { MultiNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { MultiNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , MultiGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> MultiNode { MultiNode { } } } pub use crate :: deploy :: graphs :: MultiNode ; # [cfg (stageleft_macro)] impl Node for MultiNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } } pub use graphs :: * ; pub use crate :: deploy :: LocalDeploy ; pub use crate :: deploy :: Deploy ; # [cfg (stageleft_macro)] impl < 'a , T : Deploy < 'a , Process = N , Cluster = C , Meta = M , GraphId = R > , N : Node < Meta = M > , C : Node < Meta = M > , M : Default , R , > LocalDeploy < 'a > for T { type Process = N ; type Cluster = C ; type Meta = M ; type GraphId = R ; fn has_trivial_node () -> bool { < T as Deploy < 'a > > :: has_trivial_node () } fn trivial_process (id : usize) -> Self :: Process { < T as Deploy < 'a > > :: trivial_process (id) } fn trivial_cluster (id : usize) -> Self :: Cluster { < T as Deploy < 'a > > :: trivail_cluster (id) } } pub use crate :: deploy :: ProcessSpec ; pub use crate :: deploy :: ClusterSpec ; pub use crate :: deploy :: Node ; } pub use deploy :: { ClusterSpec , Deploy , ProcessSpec } ; pub mod cycle { pub use std :: marker :: PhantomData ; pub use crate :: builder :: FlowLeaves ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: cycle :: CycleComplete ; pub use crate :: cycle :: CycleCollection ; pub use crate :: cycle :: CycleCollectionWithInitial ; pub use crate :: cycle :: HfCycle ; # [cfg (stageleft_macro)] impl < 'a , S : CycleComplete < 'a > > HfCycle < 'a , S > { pub fn complete (self , stream : S) { let ident = self . ident ; S :: complete (stream , ident) } } } pub use cycle :: HfCycle ; pub mod builder { pub use std :: cell :: RefCell ; pub use std :: collections :: HashMap ; pub use std :: marker :: PhantomData ; pub use std :: rc :: Rc ; pub use std :: time :: Duration ; pub use hydroflow :: futures :: stream :: Stream as FuturesStream ; pub use hydroflow :: { tokio , tokio_stream } ; pub use internal :: TokenStream ; pub use proc_macro2 :: Span ; pub use quote :: quote ; pub use runtime_support :: FreeVariable ; pub use stageleft :: * ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Cluster , Location , LocationId , Process } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: { HfCycle , Optional , RuntimeContext , Singleton , Stream } ; pub mod built { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use hydroflow_lang :: graph :: { eliminate_extra_unions_tees , HydroflowGraph } ; pub use super :: deploy :: { DeployFlow , DeployResult } ; pub use crate :: deploy :: { ClusterSpec , Deploy , LocalDeploy , ProcessSpec } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Cluster , Process } ; pub use crate :: HfCompiled ; pub use crate :: builder :: built :: BuiltFlow ; # [cfg (stageleft_macro)] impl < 'a > Drop for BuiltFlow < 'a > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped BuiltFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn ir (& self) -> & Vec < HfPlusLeaf < 'a > > { & self . ir } pub fn optimize_with (mut self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> BuiltFlow < 'a > { self . used = true ; BuiltFlow { ir : f (std :: mem :: take (& mut self . ir)) , processes : std :: mem :: take (& mut self . processes) , clusters : std :: mem :: take (& mut self . clusters) , used : false , _phantom : PhantomData , } } } pub fn build_inner (ir : & mut Vec < HfPlusLeaf >) -> BTreeMap < usize , HydroflowGraph > { let mut builders = BTreeMap :: new () ; let mut built_tees = HashMap :: new () ; let mut next_stmt_id = 0 ; for leaf in ir { leaf . emit (& mut builders , & mut built_tees , & mut next_stmt_id) ; } builders . into_iter () . map (| (k , v) | { let (mut flat_graph , _ , _) = v . build () ; eliminate_extra_unions_tees (& mut flat_graph) ; (k , flat_graph) }) . collect () } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn compile_no_network < D : LocalDeploy < 'a > > (mut self) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; HfCompiled { hydroflow_ir : build_inner (& mut self . ir) , extra_stmts : BTreeMap :: new () , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> BuiltFlow < 'a > { self . optimize_with (crate :: persist_pullup :: persist_pullup) } fn into_deploy < D : LocalDeploy < 'a > > (mut self) -> DeployFlow < 'a , D > { self . used = true ; let processes = if D :: has_trivial_node () { self . processes . iter () . map (| id | (* id , D :: trivial_process (* id))) . collect () } else { HashMap :: new () } ; let clusters = if D :: has_trivial_node () { self . clusters . iter () . map (| id | (* id , D :: trivial_cluster (* id))) . collect () } else { HashMap :: new () } ; DeployFlow { ir : std :: mem :: take (& mut self . ir) , nodes : processes , clusters , used : false , _phantom : PhantomData , } } pub fn with_process < P , D : LocalDeploy < 'a > > (self , process : & Process < P > , spec : impl ProcessSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_process (process , spec) } pub fn with_cluster < C , D : LocalDeploy < 'a > > (self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_cluster (cluster , spec) } pub fn compile < D : Deploy < 'a > + 'a > (self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . into_deploy :: < D > () . compile (env) } pub fn deploy < D : Deploy < 'a , CompileEnv = () > + 'a > (self , env : & mut D :: InstantiateEnv ,) -> DeployResult < 'a , D > { self . into_deploy :: < D > () . deploy (env) } } } pub mod deploy { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use proc_macro2 :: Span ; pub use stageleft :: Quoted ; pub use super :: built :: build_inner ; pub use crate :: deploy :: { LocalDeploy , Node } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: { Cluster , ClusterSpec , Deploy , HfCompiled , Process , ProcessSpec } ; pub use crate :: builder :: deploy :: DeployFlow ; # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > Drop for DeployFlow < 'a , D > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped DeployFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > DeployFlow < 'a , D > { pub fn with_process < P > (mut self , process : & Process < P > , spec : impl ProcessSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < P > () . to_string () ; self . nodes . insert (process . id , spec . build (process . id , & tag_name)) ; self } pub fn with_cluster < C > (mut self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < C > () . to_string () ; self . clusters . insert (cluster . id , spec . build (cluster . id , & tag_name)) ; self } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployFlow < 'a , D > { pub fn compile (mut self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; let mut seen_tees : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | leaf . compile_network :: < D > (env , & mut seen_tees , & self . nodes , & self . clusters)) . collect () ; let extra_stmts = self . extra_stmts (env) ; HfCompiled { hydroflow_ir : build_inner (& mut ir_leaves_networked) , extra_stmts , _phantom : PhantomData , } } fn extra_stmts (& self , env : & < D as Deploy < 'a > > :: CompileEnv) -> BTreeMap < usize , Vec < syn :: Stmt > > { let all_locations_count = self . nodes . len () + self . clusters . len () ; let mut extra_stmts : BTreeMap < usize , Vec < syn :: Stmt > > = BTreeMap :: new () ; for & c_id in self . clusters . keys () { let self_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , c_id) , Span :: call_site () ,) ; let self_id_expr = D :: cluster_self_id (env) . splice () ; extra_stmts . entry (c_id) . or_default () . push (syn :: parse_quote ! { let # self_id_ident = # self_id_expr ; }) ; for other_location in 0 .. all_locations_count { let other_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , c_id) , Span :: call_site () ,) ; let other_id_expr = D :: cluster_ids (env , c_id) . splice () ; extra_stmts . entry (other_location) . or_default () . push (syn :: parse_quote ! { let # other_id_ident = # other_id_expr ; }) ; } } extra_stmts } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a , CompileEnv = () > > DeployFlow < 'a , D > { # [must_use] pub fn deploy (mut self , env : & mut D :: InstantiateEnv) -> DeployResult < 'a , D > { self . used = true ; let mut seen_tees_instantiate : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | { leaf . compile_network :: < D > (& () , & mut seen_tees_instantiate , & self . nodes , & self . clusters ,) }) . collect () ; let mut compiled = build_inner (& mut ir_leaves_networked) ; let mut extra_stmts = self . extra_stmts (& ()) ; let mut meta = D :: Meta :: default () ; let (mut processes , mut clusters) = (std :: mem :: take (& mut self . nodes) . into_iter () . map (| (node_id , node) | { node . instantiate (env , & mut meta , compiled . remove (& node_id) . unwrap () , extra_stmts . remove (& node_id) . unwrap_or_default () ,) ; (node_id , node) }) . collect :: < HashMap < _ , _ > > () , std :: mem :: take (& mut self . clusters) . into_iter () . map (| (cluster_id , cluster) | { cluster . instantiate (env , & mut meta , compiled . remove (& cluster_id) . unwrap () , extra_stmts . remove (& cluster_id) . unwrap_or_default () ,) ; (cluster_id , cluster) }) . collect :: < HashMap < _ , _ > > () ,) ; for node in processes . values_mut () { node . update_meta (& meta) ; } for cluster in clusters . values_mut () { cluster . update_meta (& meta) ; } let mut seen_tees_connect = HashMap :: new () ; for leaf in ir_leaves_networked { leaf . connect_network (& mut seen_tees_connect) ; } DeployResult { processes , clusters , } } } pub use crate :: builder :: deploy :: DeployResult ; # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployResult < 'a , D > { pub fn get_process < P > (& self , p : & Process < P >) -> & D :: Process { let id = match p . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . processes . get (& id) . unwrap () } pub fn get_cluster < C > (& self , c : & Cluster < C >) -> & D :: Cluster { let id = match c . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . clusters . get (& id) . unwrap () } } } # [doc = " Tracks the leaves of the dataflow IR. This is referenced by"] # [doc = " `Stream` and `HfCycle` to build the IR. The inner option will"] # [doc = " be set to `None` when this builder is finalized."] pub type FlowLeaves < 'a > = Rc < RefCell < Option < Vec < HfPlusLeaf < 'a > > > > > ; pub use crate :: builder :: ClusterIds ; # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Vec < u32 > > for ClusterIds < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , & 'a Vec < u32 > > for ClusterIds < 'a > { } # [derive (Copy , Clone)] pub struct ClusterSelfId < 'a > { pub id : usize , pub _phantom : PhantomData < & 'a mut & 'a u32 > , } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < u32 > for ClusterSelfId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , u32 > for ClusterSelfId < 'a > { } pub use crate :: builder :: FlowBuilder ; # [cfg (stageleft_macro)] impl < 'a > Drop for FlowBuilder < 'a > { fn drop (& mut self) { if ! self . finalized { panic ! ("Dropped FlowBuilder without finalizing, you may have forgotten to call `with_default_optimize`, `optimize_with`, or `finalize`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > QuotedContext for FlowBuilder < 'a > { fn create () -> Self { FlowBuilder :: new () } } # [cfg (stageleft_macro)] impl < 'a > FlowBuilder < 'a > { # [allow (clippy :: new_without_default)] pub fn new () -> FlowBuilder < 'a > { FlowBuilder { ir_leaves : Rc :: new (RefCell :: new (Some (Vec :: new ()))) , nodes : RefCell :: new (vec ! []) , clusters : RefCell :: new (vec ! []) , cycle_ids : RefCell :: new (HashMap :: new ()) , next_node_id : RefCell :: new (0) , finalized : false , _phantom : PhantomData , } } pub fn finalize (mut self) -> built :: BuiltFlow < 'a > { self . finalized = true ; built :: BuiltFlow { ir : self . ir_leaves . borrow_mut () . take () . unwrap () , processes : self . nodes . replace (vec ! []) , clusters : self . clusters . replace (vec ! []) , used : false , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> built :: BuiltFlow < 'a > { self . finalize () . with_default_optimize () } pub fn optimize_with (self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> built :: BuiltFlow < 'a > { self . finalize () . optimize_with (f) } pub fn ir_leaves (& self) -> & FlowLeaves < 'a > { & self . ir_leaves } pub fn process < P > (& self) -> Process < P > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . nodes . borrow_mut () . push (id) ; Process { id , _phantom : PhantomData , } } pub fn cluster < C > (& self) -> Cluster < C > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . clusters . borrow_mut () . push (id) ; Cluster { id , _phantom : PhantomData , } } pub fn runtime_context (& self) -> RuntimeContext < 'a > { RuntimeContext { _phantom : PhantomData , } } pub fn cluster_members < C > (& self , cluster : & Cluster < C > ,) -> impl Quoted < 'a , & 'a Vec < u32 > > + Copy + 'a { ClusterIds { id : cluster . id , _phantom : PhantomData , } } pub fn cluster_self_id < C > (& self , cluster : & Cluster < C >) -> impl Quoted < 'a , u32 > + Copy + 'a { ClusterSelfId { id : cluster . id , _phantom : PhantomData , } } pub fn spin < L : Location > (& self , on : & L) -> Stream < 'a , () , Unbounded , NoTick , L > { Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Spin () , location_kind : on . id () , })) ,) } pub fn spin_batch < L : Location > (& self , on : & L , batch_size : impl Quoted < 'a , usize > + Copy + 'a ,) -> Stream < 'a , () , Bounded , Tick , L > { self . spin (on) . flat_map (q ! (move | _ | 0 .. batch_size)) . map (q ! (| _ | ())) . tick_batch () } pub fn source_stream < T , E : FuturesStream < Item = T > + Unpin , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Unbounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Stream (e . into ()) , location_kind : on . id () , })) ,) } pub fn source_iter < T , E : IntoIterator < Item = T > , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Bounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , })) ,) } pub fn singleton < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Singleton < 'a , T , Bounded , NoTick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Singleton :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,)))) ,) } pub fn singleton_first_tick < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Optional < 'a , T , Bounded , Tick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,) } pub fn source_interval < L : Location > (& self , on : & L , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , () , Unbounded , NoTick , L > { let interval = interval . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : on . id () , })) ,) } pub fn source_interval_delayed < L : Location > (& self , on : & L , delay : impl Quoted < 'a , Duration > + Copy + 'a , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , tokio :: time :: Instant , Unbounded , NoTick , L > { self . source_stream (on , q ! (tokio_stream :: wrappers :: IntervalStream :: new (tokio :: time :: interval_at (tokio :: time :: Instant :: now () + delay , interval))) ,) . tick_batch () . first () . latest () } pub fn cycle < S : CycleCollection < 'a > > (& self , on : & S :: Location) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , on . id ()) ,) } pub fn cycle_with_initial < S : CycleCollectionWithInitial < 'a > > (& self , on : & S :: Location , initial : S ,) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , initial , on . id ()) ,) } } } pub use builder :: FlowBuilder ; pub mod ir { pub use core :: panic ; pub use std :: cell :: RefCell ; pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow_lang :: graph :: FlatGraphBuilder ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: ToTokens ; pub use syn :: parse_quote ; pub use crate :: deploy :: Deploy ; pub use crate :: location :: LocationId ; pub use crate :: ir :: DebugExpr ; # [cfg (stageleft_macro)] impl From < syn :: Expr > for DebugExpr { fn from (expr : syn :: Expr) -> DebugExpr { DebugExpr (expr) } } # [cfg (stageleft_macro)] impl Deref for DebugExpr { type Target = syn :: Expr ; fn deref (& self) -> & Self :: Target { & self . 0 } } # [cfg (stageleft_macro)] impl ToTokens for DebugExpr { fn to_tokens (& self , tokens : & mut TokenStream) { self . 0 . to_tokens (tokens) ; } } # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugExpr { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "{}" , self . 0 . to_token_stream ()) } } pub use crate :: ir :: DebugInstantiate ; # [cfg (stageleft_macro)] impl < 'a > std :: fmt :: Debug for DebugInstantiate < 'a > { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<network instantiate>") } } pub use crate :: ir :: DebugPipelineFn ; # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugPipelineFn { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<function>") } } pub use crate :: ir :: HfPlusSource ; pub use crate :: ir :: HfPlusLeaf ; # [cfg (stageleft_macro)] impl < 'a > HfPlusLeaf < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . compile_network :: < D > (compile_env , s , nodes , clusters) ; } , seen_tees ,) } pub fn connect_network (self , seen_tees : & mut SeenTees < 'a >) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . connect_network (s) ; } , seen_tees ,) } pub fn transform_children (self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) -> HfPlusLeaf < 'a > { match self { HfPlusLeaf :: ForEach { f , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: ForEach { f , input } } HfPlusLeaf :: DestSink { sink , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: DestSink { sink , input } } HfPlusLeaf :: CycleSink { ident , location_kind , mut input , } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: CycleSink { ident , location_kind , input , } } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) { match self { HfPlusLeaf :: ForEach { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> for_each (# f) ; }) ; } HfPlusLeaf :: DestSink { sink , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink) ; }) ; } HfPlusLeaf :: CycleSink { ident , location_kind , input , } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; assert_eq ! (input_location_id , * location_id , "cycle_sink location mismatch") ; graph_builders . entry (* location_id) . or_default () . add_statement (parse_quote ! { # ident = # input_ident ; }) ; } } } } pub use crate :: ir :: HfPlusNode ; pub type SeenTees < 'a > = HashMap < * const RefCell < HfPlusNode < 'a > > , Rc < RefCell < HfPlusNode < 'a > > > > ; # [cfg (stageleft_macro)] impl < 'a > HfPlusNode < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (& mut self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) { self . transform_children (| n , s | n . compile_network :: < D > (compile_env , s , nodes , clusters) , seen_tees ,) ; if let HfPlusNode :: Network { from_location , to_location , instantiate_fn , .. } = self { let (sink_expr , source_expr , connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { let ((sink , source) , connect_fn) = match (from_location , to_location) { (LocationId :: Process (from) , LocationId :: Process (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: o2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Process (from) , LocationId :: Cluster (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: o2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Process (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: m2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Cluster (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: m2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } } ; (sink , source , connect_fn) } DebugInstantiate :: Finalized (_ , _ , _) => panic ! ("network already finalized") , } ; * instantiate_fn = DebugInstantiate :: Finalized (sink_expr , source_expr , connect_fn) ; } } pub fn connect_network (& mut self , seen_tees : & mut SeenTees < 'a >) { self . transform_children (| n , s | n . connect_network (s) , seen_tees) ; if let HfPlusNode :: Network { instantiate_fn , .. } = self { match instantiate_fn { DebugInstantiate :: Building () => panic ! ("network not built") , DebugInstantiate :: Finalized (_ , _ , ref connect_fn) => { connect_fn () ; } } } } pub fn transform_children (& mut self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) { match self { HfPlusNode :: Placeholder => { panic ! () ; } HfPlusNode :: Source { .. } => { } HfPlusNode :: CycleSource { .. } => { } HfPlusNode :: Tee { inner } => { if let Some (transformed) = seen_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { * inner = transformed . clone () ; } else { let transformed_cell = Rc :: new (RefCell :: new (HfPlusNode :: Placeholder)) ; seen_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , transformed_cell . clone () ,) ; let mut orig = inner . replace (HfPlusNode :: Placeholder) ; transform (& mut orig , seen_tees) ; * transformed_cell . borrow_mut () = orig ; * inner = transformed_cell ; } } HfPlusNode :: Persist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Unpersist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Delta (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Union (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossProduct (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossSingleton (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Join (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Difference (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: AntiJoin (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Map { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FlatMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Filter { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FilterMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Sort (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: DeferTick (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Enumerate (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Inspect { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Unique (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Fold { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FoldKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Reduce { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: ReduceKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Network { input , .. } => { transform (input . as_mut () , seen_tees) ; } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) -> (syn :: Ident , usize) { match self { HfPlusNode :: Placeholder => { panic ! () } HfPlusNode :: Persist (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let persist_id = * next_stmt_id ; * next_stmt_id += 1 ; let persist_ident = syn :: Ident :: new (& format ! ("stream_{}" , persist_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # persist_ident = # inner_ident -> persist ::<'static > () ; }) ; (persist_ident , location) } HfPlusNode :: Unpersist (_) => { panic ! ("Unpersist is a marker node and should have been optimized away. This is likely a compiler bug.") } HfPlusNode :: Delta (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let delta_id = * next_stmt_id ; * next_stmt_id += 1 ; let delta_ident = syn :: Ident :: new (& format ! ("stream_{}" , delta_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # delta_ident = # inner_ident -> multiset_delta () ; }) ; (delta_ident , location) } HfPlusNode :: Source { source , location_kind , } => { let source_id = * next_stmt_id ; * next_stmt_id += 1 ; let source_ident = syn :: Ident :: new (& format ! ("stream_{}" , source_id) , Span :: call_site ()) ; let source_stmt = match source { HfPlusSource :: Stream (expr) => { parse_quote ! { # source_ident = source_stream (# expr) ; } } HfPlusSource :: Iter (expr) => { parse_quote ! { # source_ident = source_iter (# expr) ; } } HfPlusSource :: Interval (expr) => { parse_quote ! { # source_ident = source_interval (# expr) ; } } HfPlusSource :: Spin () => { parse_quote ! { # source_ident = spin () ; } } } ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; graph_builders . entry (* location_id) . or_default () . add_statement (source_stmt) ; (source_ident , * location_id) } HfPlusNode :: CycleSource { ident , location_kind , } => { let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; (ident . clone () , * location_id) } HfPlusNode :: Tee { inner } => { if let Some (ret) = built_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { ret . clone () } else { let (inner_ident , inner_location_id) = inner . borrow () . emit (graph_builders , built_tees , next_stmt_id) ; let tee_id = * next_stmt_id ; * next_stmt_id += 1 ; let tee_ident = syn :: Ident :: new (& format ! ("stream_{}" , tee_id) , Span :: call_site ()) ; let builder = graph_builders . entry (inner_location_id) . or_default () ; builder . add_statement (parse_quote ! { # tee_ident = # inner_ident -> tee () ; }) ; built_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , (tee_ident . clone () , inner_location_id) ,) ; (tee_ident , inner_location_id) } } HfPlusNode :: Union (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "union inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let union_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # union_ident = union () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [0] # union_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # union_ident ; }) ; (union_ident , left_location_id) } HfPlusNode :: CrossSingleton (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "cross_singleton inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let cross_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # cross_ident = cross_singleton () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [input] # cross_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [single] # cross_ident ; }) ; (cross_ident , left_location_id) } HfPlusNode :: CrossProduct (..) | HfPlusNode :: Join (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: CrossProduct (..)) { parse_quote ! (cross_join_multiset) } else { parse_quote ! (join_multiset) } ; let (HfPlusNode :: CrossProduct (left , right) | HfPlusNode :: Join (left , right)) = self else { unreachable ! () } ; let (left_inner , left_was_persist) = if let HfPlusNode :: Persist (left) = left . as_ref () { (left , true) } else { (left , false) } ; let (right_inner , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left_inner . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right_inner . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "join / cross product inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; match (left_was_persist , right_was_persist) { (true , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'static > () ; }) ; } (true , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'tick > () ; }) ; } (false , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } (false , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } } ; builder . add_statement (parse_quote ! { # left_ident -> [0] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Difference (..) | HfPlusNode :: AntiJoin (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Difference (..)) { parse_quote ! (difference_multiset) } else { parse_quote ! (anti_join_multiset) } ; let (HfPlusNode :: Difference (left , right) | HfPlusNode :: AntiJoin (left , right)) = self else { unreachable ! () } ; let (right , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "difference / anti join inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; if right_was_persist { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } else { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } builder . add_statement (parse_quote ! { # left_ident -> [pos] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [neg] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Map { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let map_id = * next_stmt_id ; * next_stmt_id += 1 ; let map_ident = syn :: Ident :: new (& format ! ("stream_{}" , map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # map_ident = # input_ident -> map (# f) ; }) ; (map_ident , input_location_id) } HfPlusNode :: FlatMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let flat_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let flat_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , flat_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # flat_map_ident = # input_ident -> flat_map (# f) ; }) ; (flat_map_ident , input_location_id) } HfPlusNode :: Filter { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_ident = # input_ident -> filter (# f) ; }) ; (filter_ident , input_location_id) } HfPlusNode :: FilterMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_map_ident = # input_ident -> filter_map (# f) ; }) ; (filter_map_ident , input_location_id) } HfPlusNode :: Sort (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sort_id = * next_stmt_id ; * next_stmt_id += 1 ; let sort_ident = syn :: Ident :: new (& format ! ("stream_{}" , sort_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # sort_ident = # input_ident -> sort () ; }) ; (sort_ident , input_location_id) } HfPlusNode :: DeferTick (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let defer_tick_id = * next_stmt_id ; * next_stmt_id += 1 ; let defer_tick_ident = syn :: Ident :: new (& format ! ("stream_{}" , defer_tick_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # defer_tick_ident = # input_ident -> defer_tick_lazy () ; }) ; (defer_tick_ident , input_location_id) } HfPlusNode :: Enumerate (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let enumerate_id = * next_stmt_id ; * next_stmt_id += 1 ; let enumerate_ident = syn :: Ident :: new (& format ! ("stream_{}" , enumerate_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # enumerate_ident = # input_ident -> enumerate () ; }) ; (enumerate_ident , input_location_id) } HfPlusNode :: Inspect { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let inspect_id = * next_stmt_id ; * next_stmt_id += 1 ; let inspect_ident = syn :: Ident :: new (& format ! ("stream_{}" , inspect_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # inspect_ident = # input_ident -> inspect (# f) ; }) ; (inspect_ident , input_location_id) } HfPlusNode :: Unique (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let unique_id = * next_stmt_id ; * next_stmt_id += 1 ; let unique_ident = syn :: Ident :: new (& format ! ("stream_{}" , unique_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # unique_ident = # input_ident -> unique ::<'tick > () ; }) ; (unique_ident , input_location_id) } HfPlusNode :: Fold { .. } | HfPlusNode :: FoldKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Fold { .. }) { parse_quote ! (fold) } else { parse_quote ! (fold_keyed) } ; let (HfPlusNode :: Fold { init , acc , input } | HfPlusNode :: FoldKeyed { init , acc , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let fold_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'static > (# init , # acc) ; }) ; } else { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'tick > (# init , # acc) ; }) ; } (fold_ident , input_location_id) } HfPlusNode :: Reduce { .. } | HfPlusNode :: ReduceKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Reduce { .. }) { parse_quote ! (reduce) } else { parse_quote ! (reduce_keyed) } ; let (HfPlusNode :: Reduce { f , input } | HfPlusNode :: ReduceKeyed { f , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let reduce_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'static > (# f) ; }) ; } else { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'tick > (# f) ; }) ; } (reduce_ident , input_location_id) } HfPlusNode :: Network { from_location : _ , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input , } => { let (sink_expr , source_expr , _connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { panic ! ("Expected the network to be finalized") } DebugInstantiate :: Finalized (sink , source , connect_fn) => { (sink , source , connect_fn) } } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sender_builder = graph_builders . entry (input_location_id) . or_default () ; if let Some (serialize_pipeline) = serialize_pipeline { sender_builder . add_statement (parse_quote ! { # input_ident -> # serialize_pipeline -> dest_sink (# sink_expr) ; }) ; } else { sender_builder . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink_expr) ; }) ; } let to_id = match to_location { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let receiver_builder = graph_builders . entry (* to_id) . or_default () ; let receiver_stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let receiver_stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , receiver_stream_id) , Span :: call_site ()) ; if let Some (deserialize_pipeline) = deserialize_pipeline { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) -> # deserialize_pipeline ; }) ; } else { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) ; }) ; } (receiver_stream_ident , * to_id) } } } } } pub mod persist_pullup { pub use std :: cell :: RefCell ; pub use std :: collections :: HashSet ; pub use std :: ops :: Deref ; pub use crate :: ir :: * ; pub fn persist_pullup_node < 'a > (node : & mut HfPlusNode < 'a > , seen_tees : & mut SeenTees < 'a > , persist_pulled_tees : & mut HashSet < * const RefCell < HfPlusNode < 'a > > > ,) { node . transform_children (| n , s | persist_pullup_node (n , s , persist_pulled_tees) , seen_tees ,) ; match node { HfPlusNode :: Unpersist (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Unpersist (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Delta (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Delta (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Tee { inner } => { if persist_pulled_tees . contains (& (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >)) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } else { let inner_borrow = inner . borrow () ; if let HfPlusNode :: Persist (_) = inner_borrow . deref () { drop (inner_borrow) ; persist_pulled_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >) ; if let HfPlusNode :: Persist (box behind_persist) = inner . replace (HfPlusNode :: Placeholder) { * inner . borrow_mut () = behind_persist ; } else { unreachable ! () } * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } } } HfPlusNode :: Map { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Map { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Map { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: FlatMap { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: FlatMap { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: FlatMap { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Filter { f : _ , input : HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Filter { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Filter { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Network { input : box HfPlusNode :: Persist (_) , .. } => { if let HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Union (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Union (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Union (left , right))) ; } else { unreachable ! () } } HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: CrossProduct (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,) ,)))) ; } else { unreachable ! () } } HfPlusNode :: Join (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Join (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: Join (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,))))) ; } else { unreachable ! () } } _ => { } } } pub fn persist_pullup (ir : Vec < HfPlusLeaf >) -> Vec < HfPlusLeaf > { let mut seen_tees = Default :: default () ; let mut persist_pulled_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| n , s | persist_pullup_node (n , s , & mut persist_pulled_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn persist_pullup_through_map () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } # [test] fn persist_pullup_behind_tee () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; let before_tee = flow . source_iter (& process , q ! (0 .. 10)) . tick_batch () . persist () ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } } } pub mod profiler { pub use std :: cell :: RefCell ; pub use hydroflow :: futures :: channel :: mpsc :: UnboundedSender ; pub use stageleft :: * ; pub use crate as hydroflow_plus ; pub use crate :: ir :: * ; pub use crate :: RuntimeContext ; pub fn increment_counter (count : & mut u64) { * count += 1 ; } pub fn quoted_any_fn < 'a , F : Fn (& usize) + 'a , Q : IntoQuotedMut < 'a , F > > (q : Q) -> Q { q } # [doc = " Add a profiling node before each node to count the cardinality of its input"] pub fn add_profiling_node < 'a > (node : & mut HfPlusNode < 'a > , _context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > , id : & mut u32 , seen_tees : & mut SeenTees < 'a > ,) { let my_id = * id ; * id += 1 ; node . transform_children (| node , seen_tees | { add_profiling_node (node , _context , counters , counter_queue , id , seen_tees) } , seen_tees ,) ; let orig_node = std :: mem :: replace (node , HfPlusNode :: Placeholder) ; * node = HfPlusNode :: Inspect { f : quoted_any_fn (q ! ({ counter_queue . borrow () . unbounded_send ((my_id as usize , counters . borrow () [my_id as usize])) . unwrap () ; counters . borrow_mut () [my_id as usize] = 0 ; move | _ | { hydroflow_plus :: profiler :: increment_counter (& mut counters . borrow_mut () [my_id as usize] ,) ; } })) . splice () . into () , input : Box :: new (orig_node) , } } # [doc = " Count the cardinality of each input and periodically output to a file"] pub fn profiling < 'a > (ir : Vec < HfPlusLeaf < 'a > > , context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > ,) -> Vec < HfPlusLeaf < 'a > > { let mut id = 0 ; let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | { add_profiling_node (node , context , counters , counter_queue , & mut id , seen_tees) } , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn profiler_wrapping_all_operators () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let runtime_context = flow . runtime_context () ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (& built . ir ()) ; let counters = RuntimeData :: new ("Fake") ; let counter_queue = RuntimeData :: new ("Fake") ; let pushed_down = built . with_default_optimize () . optimize_with (| ir | super :: profiling (ir , runtime_context , counters , counter_queue)) ; insta :: assert_debug_snapshot ! (& pushed_down . ir ()) ; let _ = pushed_down . compile_no_network :: < MultiGraph > () ; } } } pub mod properties { pub use std :: collections :: HashSet ; pub use stageleft :: * ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , SeenTees } ; pub use crate :: properties :: PropertyDatabase ; # [doc = " Allows us to convert the hydroflow datatype for folds to a binary operation for the algebra"] # [doc = " property tests."] # [allow (dead_code)] pub fn convert_hf_to_binary < I , A : Default , F : Fn (& mut A , I) > (f : F) -> impl Fn (I , I) -> A { move | a , b | { let mut acc = Default :: default () ; f (& mut acc , a) ; f (& mut acc , b) ; acc } } # [cfg (stageleft_macro)] impl PropertyDatabase { # [doc = " Tags the expression as commutative."] pub fn add_commutative_tag < 'a , I , A , F : Fn (& mut A , I) , Q : Quoted < 'a , F > + Clone > (& mut self , expr : Q ,) -> Q { let expr_clone = expr . clone () ; self . commutative . insert (expr_clone . splice ()) ; expr } pub fn is_tagged_commutative (& self , expr : & syn :: Expr) -> bool { self . commutative . contains (expr) } } pub fn properties_optimize_node < 'a > (node : & mut HfPlusNode < 'a > , db : & PropertyDatabase , seen_tees : & mut SeenTees < 'a > ,) { node . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , seen_tees ,) ; match node { HfPlusNode :: ReduceKeyed { f , .. } if db . is_tagged_commutative (& f . 0) => { dbg ! ("IDENTIFIED COMMUTATIVE OPTIMIZATION for {:?}" , & f) ; } _ => { } } } pub fn properties_optimize < 'a > (ir : Vec < HfPlusLeaf < 'a > > , db : & PropertyDatabase ,) -> Vec < HfPlusLeaf < 'a > > { let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use super :: * ; use crate :: deploy :: SingleProcessGraph ; use crate :: FlowBuilder ; # [test] fn test_property_database () { let mut db = PropertyDatabase :: default () ; assert ! (! db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; let _ = db . add_commutative_tag (q ! (| a : & mut i32 , b : i32 | * a += b)) ; assert ! (db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; } # [test] fn test_property_optimized () { let flow = FlowBuilder :: new () ; let mut database = PropertyDatabase :: default () ; let process = flow . process :: < () > () ; let counter_func = q ! (| count : & mut i32 , _ | * count += 1) ; let _ = database . add_commutative_tag (counter_func) ; flow . source_iter (& process , q ! (vec ! [])) . map (q ! (| string : String | (string , ()))) . tick_batch () . fold_keyed (q ! (|| 0) , counter_func) . all_ticks () . for_each (q ! (| (string , count) | println ! ("{}: {}" , string , count))) ; let built = flow . finalize () . optimize_with (| ir | properties_optimize (ir , & database)) . with_default_optimize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let _ = built . compile_no_network :: < SingleProcessGraph > () ; } } } pub use crate :: RuntimeContext ; # [cfg (stageleft_macro)] impl Copy for RuntimeContext < '_ > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Context > for RuntimeContext < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (quote ! (& context))) } } pub use crate :: HfCompiled ; # [cfg (stageleft_macro)] impl < 'a , ID > HfCompiled < 'a , ID > { pub fn hydroflow_ir (& self) -> & BTreeMap < usize , HydroflowGraph > { & self . hydroflow_ir } } # [cfg (stageleft_macro)] impl < 'a > HfCompiled < 'a , usize > { pub fn with_dynamic_id (self , id : impl Quoted < 'a , usize >) -> HfBuiltWithId < 'a > { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; let mut conditioned_tokens = None ; for (subgraph_id , flat_graph) in self . hydroflow_ir { let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; let my_extra_stmts = self . extra_stmts . get (& subgraph_id) . cloned () . unwrap_or_default () ; if let Some (conditioned_tokens) = conditioned_tokens . as_mut () { * conditioned_tokens = syn :: parse_quote ! { # conditioned_tokens else if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } } ; } else { conditioned_tokens = Some (syn :: parse_quote ! { if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } }) ; } } let conditioned_tokens : TokenStream = conditioned_tokens . unwrap () ; let id = id . splice () ; HfBuiltWithId { tokens : syn :: parse_quote ! ({ let __given_id = # id ; # conditioned_tokens else { panic ! ("Invalid node id: {}" , __given_id) ; } }) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfCompiled < 'a , () > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfCompiled < 'a , () > { fn to_tokens (mut self) -> (Option < TokenStream > , Option < TokenStream >) { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; if self . hydroflow_ir . len () != 1 { panic ! ("Expected exactly one subgraph in the Hydroflow IR") ; } let flat_graph = self . hydroflow_ir . remove (& 0) . unwrap () ; let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; (None , Some (tokens)) } } pub use crate :: HfBuiltWithId ; # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfBuiltWithId < 'a > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfBuiltWithId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (self . tokens)) } }
[INFO] [stdout]   |
[INFO] [stdout] help: ...otherwise replace it with an invocation of macro `deref`
[INFO] [stdout]   |
[INFO] [stdout] 1 - pub use std :: collections :: BTreeMap ; pub use std :: marker :: PhantomData ; pub use hydroflow :: scheduled :: context :: Context ; pub use hydroflow :: scheduled :: graph :: Hydroflow ; pub use hydroflow :: * ; pub use lang :: graph :: { partition_graph , HydroflowGraph } ; pub use proc_macro2 :: TokenStream ; pub use quote :: quote ; pub use stageleft :: runtime_support :: FreeVariable ; pub use stageleft :: Quoted ; pub mod runtime_support { pub use bincode ; } pub mod stream { pub use std :: cell :: RefCell ; pub use std :: hash :: Hash ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow :: bytes :: Bytes ; pub use hydroflow :: futures :: Sink ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: quote ; pub use serde :: de :: DeserializeOwned ; pub use serde :: Serialize ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use syn :: parse_quote ; pub use crate :: builder :: { ClusterIds , FlowLeaves } ; pub use crate :: cycle :: { CycleCollection , CycleComplete } ; pub use crate :: ir :: { DebugInstantiate , HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { CanSend , Location , LocationId } ; pub use crate :: { Cluster , Optional , Singleton } ; pub use crate :: stream :: Unbounded ; pub use crate :: stream :: Bounded ; pub use crate :: stream :: NoTick ; pub use crate :: stream :: Tick ; pub use crate :: stream :: Stream ; # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Stream { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Stream < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Stream { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , C , N > > ,) -> Stream < 'a , (T , O) , W , C , N > where O : Clone , { let other : Optional < 'a , O , Bounded , C , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn cross_product < O > (self , other : Stream < 'a , O , W , C , N >) -> Stream < 'a , (T , O) , W , C , N > where T : Clone , O : Clone , { if self . location_kind != other . location_kind { panic ! ("cross_product must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossProduct (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn union (self , other : Stream < 'a , T , W , C , N >) -> Stream < 'a , T , W , C , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn dest_sink < S : Unpin + Sink < T > + 'a > (self , sink : impl Quoted < 'a , S >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: DestSink { sink : sink . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn first (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } # [doc = " Allow this stream through if the other stream has elements, otherwise the output is empty."] pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } # [doc = " Allow this stream through if the other stream is empty, otherwise the output is empty."] pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn enumerate (self) -> Stream < 'a , (usize , T) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Enumerate (Box :: new (self . ir_node . into_inner ())) ,) } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn sort (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Ord , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Sort (Box :: new (self . ir_node . into_inner ())) ,) } pub fn count (self) -> Singleton < 'a , usize , Bounded , Tick , N > { self . fold (q ! (|| 0usize) , q ! (| count , _ | * count += 1)) } pub fn delta (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } pub fn unique (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Eq + Hash , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unique (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn tick_batch (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_prefix (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { self . tick_batch () . persist () } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn for_each < F : Fn (T) + 'a > (self , f : impl IntoQuotedMut < 'a , F >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: ForEach { input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , f : f . splice () . into () , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Unbounded , NoTick , N > { pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . tick_batch () . continue_if (samples . first ()) . all_ticks () } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Unbounded , NoTick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , C , N : Location > Stream < 'a , T , Bounded , C , N > { pub fn filter_not_in (self , other : Stream < 'a , T , Bounded , C , N >) -> Stream < 'a , T , Bounded , C , N > where T : Eq + Hash , { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Difference (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Stream < 'a , & T , W , C , N > { pub fn cloned (self) -> Stream < 'a , T , W , C , N > { self . map (q ! (| d | d . clone ())) } } # [cfg (stageleft_macro)] impl < 'a , K , V1 , W , C , N : Location > Stream < 'a , (K , V1) , W , C , N > { pub fn join < W2 , V2 > (self , n : Stream < 'a , (K , V2) , W2 , C , N > ,) -> Stream < 'a , (K , (V1 , V2)) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Join (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } pub fn anti_join < W2 > (self , n : Stream < 'a , K , W2 , C , N >) -> Stream < 'a , (K , V1) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("anti_join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: AntiJoin (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , K : Eq + Hash , V , N : Location > Stream < 'a , (K , V) , Bounded , Tick , N > { pub fn fold_keyed < A , I : Fn () -> A + 'a , F : Fn (& mut A , V) + 'a > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , A) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FoldKeyed { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce_keyed < F : Fn (& mut V , V) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , V) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: ReduceKeyed { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } pub fn get_this_crate () -> TokenStream { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , Span :: call_site ()) ; quote ! { # ident } } } } pub fn serialize_bincode < T : Serialize > (is_demux : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if is_demux { parse_quote ! { map (| (id , data) | { (id , # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into ()) }) } } else { parse_quote ! { map (| data | { # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into () }) } } } pub fn deserialize_bincode < T : DeserializeOwned > (tagged : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if tagged { parse_quote ! { map (| res | { let (id , b) = res . unwrap () ; (id , # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& b) . unwrap ()) }) } } else { parse_quote ! { map (| res | { # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& res . unwrap ()) . unwrap () }) } } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn send_bincode < N2 : Location , CoreType > (self , other : & N2 ,) -> Stream < 'a , N :: Out < CoreType > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T > , CoreType : Serialize + DeserializeOwned , { let serialize_pipeline = Some (serialize_bincode :: < CoreType > (N :: is_demux ())) ; let deserialize_pipeline = Some (deserialize_bincode :: < CoreType > (N :: is_tagged ())) ; Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bytes < N2 : Location > (self , other : & N2 ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T > , { Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline : None , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline : if N :: is_tagged () { Some (parse_quote ! (map (| (id , b) | (id , b . unwrap () . freeze ())))) } else { Some (parse_quote ! (map (| b | b . unwrap () . freeze ()))) } , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bincode_interleaved < N2 : Location , Tag , CoreType > (self , other : & N2 ,) -> Stream < 'a , CoreType , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T , Out < CoreType > = (Tag , CoreType) > , CoreType : Serialize + DeserializeOwned , { self . send_bincode :: < N2 , CoreType > (other) . map (q ! (| (_ , b) | b)) } pub fn send_bytes_interleaved < N2 : Location , Tag > (self , other : & N2 ,) -> Stream < 'a , Bytes , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T , Out < Bytes > = (Tag , Bytes) > , { self . send_bytes :: < N2 > (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bincode < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < T > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) > , T : Clone + Serialize + DeserializeOwned , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bincode (other) } pub fn broadcast_bincode_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , T , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) , Out < T > = (Tag , T) > + 'a , T : Clone + Serialize + DeserializeOwned , { self . broadcast_bincode (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bytes < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) > + 'a , T : Clone , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bytes (other) } pub fn broadcast_bytes_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , Bytes , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) , Out < Bytes > = (Tag , Bytes) > + 'a , T : Clone , { self . broadcast_bytes (other) . map (q ! (| (_ , b) | b)) } } } pub use stream :: { Bounded , NoTick , Stream , Tick , Unbounded } ; pub mod singleton { pub use std :: cell :: RefCell ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use crate :: builder :: FlowLeaves ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial , CycleComplete } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: Stream ; pub use crate :: singleton :: CrossResult ; # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Singleton < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Singleton :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } pub use crate :: singleton :: Singleton ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Singleton { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleComplete < 'a > for Singleton < 'a , T , Bounded , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleCollectionWithInitial < 'a > for Singleton < 'a , T , Bounded , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , initial : Self , l : LocationId ,) -> Self { Singleton :: new (l , ir_leaves , HfPlusNode :: Union (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , }) , initial . ir_node . into_inner () . into () ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Singleton < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Singleton { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , U , W , C , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (Self :: other_ir_node (other)) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Singleton < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CrossSingleton (Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , Box :: new (HfPlusNode :: Unpersist (Box :: new (Self :: other_ir_node (other)))) ,))) ,) } } pub use crate :: singleton :: Optional ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Optional { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } pub fn some (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: new (singleton . location_kind , singleton . ir_leaves , singleton . ir_node . into_inner () ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > From < Singleton < 'a , T , W , C , N > > for Optional < 'a , T , W , C , N > { fn from (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: some (singleton) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Optional < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Optional { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn into_stream (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , Tick , N > > ,) -> Optional < 'a , (T , O) , Bounded , Tick , N > where O : Clone , { let other : Optional < 'a , O , Bounded , Tick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn union (self , other : Optional < 'a , T , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Optional < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_samples (self) -> Stream < 'a , T , Unbounded , NoTick , N > { self . latest_tick () . all_ticks () } pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . latest_tick () . continue_if (samples . first ()) . latest () . tick_samples () } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Unbounded , NoTick , N > > ,) -> Optional < 'a , (T , O) , Unbounded , NoTick , N > where O : Clone , { let other : Optional < 'a , O , Unbounded , NoTick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } self . latest_tick () . cross_singleton (other . latest_tick ()) . latest () } } } pub use singleton :: { Optional , Singleton } ; pub mod location { pub use std :: marker :: PhantomData ; pub use crate :: location :: LocationId ; pub use crate :: location :: Location ; pub use crate :: location :: Process ; # [cfg (stageleft_macro)] impl < P > Clone for Process < P > { fn clone (& self) -> Self { Process { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < P > Location for Process < P > { fn id (& self) -> LocationId { LocationId :: Process (self . id) } } pub use crate :: location :: Cluster ; # [cfg (stageleft_macro)] impl < C > Clone for Cluster < C > { fn clone (& self) -> Self { Cluster { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < C > Location for Cluster < C > { fn id (& self) -> LocationId { LocationId :: Cluster (self . id) } } pub use crate :: location :: CanSend ; # [cfg (stageleft_macro)] impl < P1 , P2 > CanSend < Process < P2 > > for Process < P1 > { type In < T > = T ; type Out < T > = T ; fn is_demux () -> bool { false } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < P1 , C2 > CanSend < Cluster < C2 > > for Process < P1 > { type In < T > = (u32 , T) ; type Out < T > = T ; fn is_demux () -> bool { true } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < C1 , P2 > CanSend < Process < P2 > > for Cluster < C1 > { type In < T > = T ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { false } fn is_tagged () -> bool { true } } # [cfg (stageleft_macro)] impl < C1 , C2 > CanSend < Cluster < C2 > > for Cluster < C1 > { type In < T > = (u32 , T) ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { true } fn is_tagged () -> bool { true } } } pub use location :: { Cluster , Process } ; pub mod deploy { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use stageleft :: Quoted ; pub mod graphs { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use super :: { LocalDeploy , Node , ProcessSpec } ; pub use crate :: deploy :: graphs :: SingleProcessGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for SingleProcessGraph { type Process = SingleNode ; type Cluster = SingleNode ; type Meta = () ; type GraphId = () ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { SingleNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { SingleNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , SingleProcessGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> SingleNode { SingleNode { } } } pub use crate :: deploy :: graphs :: SingleNode ; # [cfg (stageleft_macro)] impl Node for SingleNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } pub use crate :: deploy :: graphs :: MultiGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for MultiGraph { type Process = MultiNode ; type Cluster = MultiNode ; type Meta = () ; type GraphId = usize ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { MultiNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { MultiNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , MultiGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> MultiNode { MultiNode { } } } pub use crate :: deploy :: graphs :: MultiNode ; # [cfg (stageleft_macro)] impl Node for MultiNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } } pub use graphs :: * ; pub use crate :: deploy :: LocalDeploy ; pub use crate :: deploy :: Deploy ; # [cfg (stageleft_macro)] impl < 'a , T : Deploy < 'a , Process = N , Cluster = C , Meta = M , GraphId = R > , N : Node < Meta = M > , C : Node < Meta = M > , M : Default , R , > LocalDeploy < 'a > for T { type Process = N ; type Cluster = C ; type Meta = M ; type GraphId = R ; fn has_trivial_node () -> bool { < T as Deploy < 'a > > :: has_trivial_node () } fn trivial_process (id : usize) -> Self :: Process { < T as Deploy < 'a > > :: trivial_process (id) } fn trivial_cluster (id : usize) -> Self :: Cluster { < T as Deploy < 'a > > :: trivail_cluster (id) } } pub use crate :: deploy :: ProcessSpec ; pub use crate :: deploy :: ClusterSpec ; pub use crate :: deploy :: Node ; } pub use deploy :: { ClusterSpec , Deploy , ProcessSpec } ; pub mod cycle { pub use std :: marker :: PhantomData ; pub use crate :: builder :: FlowLeaves ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: cycle :: CycleComplete ; pub use crate :: cycle :: CycleCollection ; pub use crate :: cycle :: CycleCollectionWithInitial ; pub use crate :: cycle :: HfCycle ; # [cfg (stageleft_macro)] impl < 'a , S : CycleComplete < 'a > > HfCycle < 'a , S > { pub fn complete (self , stream : S) { let ident = self . ident ; S :: complete (stream , ident) } } } pub use cycle :: HfCycle ; pub mod builder { pub use std :: cell :: RefCell ; pub use std :: collections :: HashMap ; pub use std :: marker :: PhantomData ; pub use std :: rc :: Rc ; pub use std :: time :: Duration ; pub use hydroflow :: futures :: stream :: Stream as FuturesStream ; pub use hydroflow :: { tokio , tokio_stream } ; pub use internal :: TokenStream ; pub use proc_macro2 :: Span ; pub use quote :: quote ; pub use runtime_support :: FreeVariable ; pub use stageleft :: * ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Cluster , Location , LocationId , Process } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: { HfCycle , Optional , RuntimeContext , Singleton , Stream } ; pub mod built { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use hydroflow_lang :: graph :: { eliminate_extra_unions_tees , HydroflowGraph } ; pub use super :: deploy :: { DeployFlow , DeployResult } ; pub use crate :: deploy :: { ClusterSpec , Deploy , LocalDeploy , ProcessSpec } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Cluster , Process } ; pub use crate :: HfCompiled ; pub use crate :: builder :: built :: BuiltFlow ; # [cfg (stageleft_macro)] impl < 'a > Drop for BuiltFlow < 'a > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped BuiltFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn ir (& self) -> & Vec < HfPlusLeaf < 'a > > { & self . ir } pub fn optimize_with (mut self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> BuiltFlow < 'a > { self . used = true ; BuiltFlow { ir : f (std :: mem :: take (& mut self . ir)) , processes : std :: mem :: take (& mut self . processes) , clusters : std :: mem :: take (& mut self . clusters) , used : false , _phantom : PhantomData , } } } pub fn build_inner (ir : & mut Vec < HfPlusLeaf >) -> BTreeMap < usize , HydroflowGraph > { let mut builders = BTreeMap :: new () ; let mut built_tees = HashMap :: new () ; let mut next_stmt_id = 0 ; for leaf in ir { leaf . emit (& mut builders , & mut built_tees , & mut next_stmt_id) ; } builders . into_iter () . map (| (k , v) | { let (mut flat_graph , _ , _) = v . build () ; eliminate_extra_unions_tees (& mut flat_graph) ; (k , flat_graph) }) . collect () } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn compile_no_network < D : LocalDeploy < 'a > > (mut self) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; HfCompiled { hydroflow_ir : build_inner (& mut self . ir) , extra_stmts : BTreeMap :: new () , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> BuiltFlow < 'a > { self . optimize_with (crate :: persist_pullup :: persist_pullup) } fn into_deploy < D : LocalDeploy < 'a > > (mut self) -> DeployFlow < 'a , D > { self . used = true ; let processes = if D :: has_trivial_node () { self . processes . iter () . map (| id | (* id , D :: trivial_process (* id))) . collect () } else { HashMap :: new () } ; let clusters = if D :: has_trivial_node () { self . clusters . iter () . map (| id | (* id , D :: trivial_cluster (* id))) . collect () } else { HashMap :: new () } ; DeployFlow { ir : std :: mem :: take (& mut self . ir) , nodes : processes , clusters , used : false , _phantom : PhantomData , } } pub fn with_process < P , D : LocalDeploy < 'a > > (self , process : & Process < P > , spec : impl ProcessSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_process (process , spec) } pub fn with_cluster < C , D : LocalDeploy < 'a > > (self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_cluster (cluster , spec) } pub fn compile < D : Deploy < 'a > + 'a > (self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . into_deploy :: < D > () . compile (env) } pub fn deploy < D : Deploy < 'a , CompileEnv = () > + 'a > (self , env : & mut D :: InstantiateEnv ,) -> DeployResult < 'a , D > { self . into_deploy :: < D > () . deploy (env) } } } pub mod deploy { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use proc_macro2 :: Span ; pub use stageleft :: Quoted ; pub use super :: built :: build_inner ; pub use crate :: deploy :: { LocalDeploy , Node } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: { Cluster , ClusterSpec , Deploy , HfCompiled , Process , ProcessSpec } ; pub use crate :: builder :: deploy :: DeployFlow ; # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > Drop for DeployFlow < 'a , D > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped DeployFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > DeployFlow < 'a , D > { pub fn with_process < P > (mut self , process : & Process < P > , spec : impl ProcessSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < P > () . to_string () ; self . nodes . insert (process . id , spec . build (process . id , & tag_name)) ; self } pub fn with_cluster < C > (mut self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < C > () . to_string () ; self . clusters . insert (cluster . id , spec . build (cluster . id , & tag_name)) ; self } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployFlow < 'a , D > { pub fn compile (mut self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; let mut seen_tees : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | leaf . compile_network :: < D > (env , & mut seen_tees , & self . nodes , & self . clusters)) . collect () ; let extra_stmts = self . extra_stmts (env) ; HfCompiled { hydroflow_ir : build_inner (& mut ir_leaves_networked) , extra_stmts , _phantom : PhantomData , } } fn extra_stmts (& self , env : & < D as Deploy < 'a > > :: CompileEnv) -> BTreeMap < usize , Vec < syn :: Stmt > > { let all_locations_count = self . nodes . len () + self . clusters . len () ; let mut extra_stmts : BTreeMap < usize , Vec < syn :: Stmt > > = BTreeMap :: new () ; for & c_id in self . clusters . keys () { let self_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , c_id) , Span :: call_site () ,) ; let self_id_expr = D :: cluster_self_id (env) . splice () ; extra_stmts . entry (c_id) . or_default () . push (syn :: parse_quote ! { let # self_id_ident = # self_id_expr ; }) ; for other_location in 0 .. all_locations_count { let other_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , c_id) , Span :: call_site () ,) ; let other_id_expr = D :: cluster_ids (env , c_id) . splice () ; extra_stmts . entry (other_location) . or_default () . push (syn :: parse_quote ! { let # other_id_ident = # other_id_expr ; }) ; } } extra_stmts } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a , CompileEnv = () > > DeployFlow < 'a , D > { # [must_use] pub fn deploy (mut self , env : & mut D :: InstantiateEnv) -> DeployResult < 'a , D > { self . used = true ; let mut seen_tees_instantiate : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | { leaf . compile_network :: < D > (& () , & mut seen_tees_instantiate , & self . nodes , & self . clusters ,) }) . collect () ; let mut compiled = build_inner (& mut ir_leaves_networked) ; let mut extra_stmts = self . extra_stmts (& ()) ; let mut meta = D :: Meta :: default () ; let (mut processes , mut clusters) = (std :: mem :: take (& mut self . nodes) . into_iter () . map (| (node_id , node) | { node . instantiate (env , & mut meta , compiled . remove (& node_id) . unwrap () , extra_stmts . remove (& node_id) . unwrap_or_default () ,) ; (node_id , node) }) . collect :: < HashMap < _ , _ > > () , std :: mem :: take (& mut self . clusters) . into_iter () . map (| (cluster_id , cluster) | { cluster . instantiate (env , & mut meta , compiled . remove (& cluster_id) . unwrap () , extra_stmts . remove (& cluster_id) . unwrap_or_default () ,) ; (cluster_id , cluster) }) . collect :: < HashMap < _ , _ > > () ,) ; for node in processes . values_mut () { node . update_meta (& meta) ; } for cluster in clusters . values_mut () { cluster . update_meta (& meta) ; } let mut seen_tees_connect = HashMap :: new () ; for leaf in ir_leaves_networked { leaf . connect_network (& mut seen_tees_connect) ; } DeployResult { processes , clusters , } } } pub use crate :: builder :: deploy :: DeployResult ; # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployResult < 'a , D > { pub fn get_process < P > (& self , p : & Process < P >) -> & D :: Process { let id = match p . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . processes . get (& id) . unwrap () } pub fn get_cluster < C > (& self , c : & Cluster < C >) -> & D :: Cluster { let id = match c . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . clusters . get (& id) . unwrap () } } } # [doc = " Tracks the leaves of the dataflow IR. This is referenced by"] # [doc = " `Stream` and `HfCycle` to build the IR. The inner option will"] # [doc = " be set to `None` when this builder is finalized."] pub type FlowLeaves < 'a > = Rc < RefCell < Option < Vec < HfPlusLeaf < 'a > > > > > ; pub use crate :: builder :: ClusterIds ; # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Vec < u32 > > for ClusterIds < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , & 'a Vec < u32 > > for ClusterIds < 'a > { } # [derive (Copy , Clone)] pub struct ClusterSelfId < 'a > { pub id : usize , pub _phantom : PhantomData < & 'a mut & 'a u32 > , } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < u32 > for ClusterSelfId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , u32 > for ClusterSelfId < 'a > { } pub use crate :: builder :: FlowBuilder ; # [cfg (stageleft_macro)] impl < 'a > Drop for FlowBuilder < 'a > { fn drop (& mut self) { if ! self . finalized { panic ! ("Dropped FlowBuilder without finalizing, you may have forgotten to call `with_default_optimize`, `optimize_with`, or `finalize`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > QuotedContext for FlowBuilder < 'a > { fn create () -> Self { FlowBuilder :: new () } } # [cfg (stageleft_macro)] impl < 'a > FlowBuilder < 'a > { # [allow (clippy :: new_without_default)] pub fn new () -> FlowBuilder < 'a > { FlowBuilder { ir_leaves : Rc :: new (RefCell :: new (Some (Vec :: new ()))) , nodes : RefCell :: new (vec ! []) , clusters : RefCell :: new (vec ! []) , cycle_ids : RefCell :: new (HashMap :: new ()) , next_node_id : RefCell :: new (0) , finalized : false , _phantom : PhantomData , } } pub fn finalize (mut self) -> built :: BuiltFlow < 'a > { self . finalized = true ; built :: BuiltFlow { ir : self . ir_leaves . borrow_mut () . take () . unwrap () , processes : self . nodes . replace (vec ! []) , clusters : self . clusters . replace (vec ! []) , used : false , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> built :: BuiltFlow < 'a > { self . finalize () . with_default_optimize () } pub fn optimize_with (self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> built :: BuiltFlow < 'a > { self . finalize () . optimize_with (f) } pub fn ir_leaves (& self) -> & FlowLeaves < 'a > { & self . ir_leaves } pub fn process < P > (& self) -> Process < P > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . nodes . borrow_mut () . push (id) ; Process { id , _phantom : PhantomData , } } pub fn cluster < C > (& self) -> Cluster < C > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . clusters . borrow_mut () . push (id) ; Cluster { id , _phantom : PhantomData , } } pub fn runtime_context (& self) -> RuntimeContext < 'a > { RuntimeContext { _phantom : PhantomData , } } pub fn cluster_members < C > (& self , cluster : & Cluster < C > ,) -> impl Quoted < 'a , & 'a Vec < u32 > > + Copy + 'a { ClusterIds { id : cluster . id , _phantom : PhantomData , } } pub fn cluster_self_id < C > (& self , cluster : & Cluster < C >) -> impl Quoted < 'a , u32 > + Copy + 'a { ClusterSelfId { id : cluster . id , _phantom : PhantomData , } } pub fn spin < L : Location > (& self , on : & L) -> Stream < 'a , () , Unbounded , NoTick , L > { Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Spin () , location_kind : on . id () , })) ,) } pub fn spin_batch < L : Location > (& self , on : & L , batch_size : impl Quoted < 'a , usize > + Copy + 'a ,) -> Stream < 'a , () , Bounded , Tick , L > { self . spin (on) . flat_map (q ! (move | _ | 0 .. batch_size)) . map (q ! (| _ | ())) . tick_batch () } pub fn source_stream < T , E : FuturesStream < Item = T > + Unpin , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Unbounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Stream (e . into ()) , location_kind : on . id () , })) ,) } pub fn source_iter < T , E : IntoIterator < Item = T > , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Bounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , })) ,) } pub fn singleton < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Singleton < 'a , T , Bounded , NoTick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Singleton :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,)))) ,) } pub fn singleton_first_tick < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Optional < 'a , T , Bounded , Tick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,) } pub fn source_interval < L : Location > (& self , on : & L , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , () , Unbounded , NoTick , L > { let interval = interval . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : on . id () , })) ,) } pub fn source_interval_delayed < L : Location > (& self , on : & L , delay : impl Quoted < 'a , Duration > + Copy + 'a , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , tokio :: time :: Instant , Unbounded , NoTick , L > { self . source_stream (on , q ! (tokio_stream :: wrappers :: IntervalStream :: new (tokio :: time :: interval_at (tokio :: time :: Instant :: now () + delay , interval))) ,) . tick_batch () . first () . latest () } pub fn cycle < S : CycleCollection < 'a > > (& self , on : & S :: Location) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , on . id ()) ,) } pub fn cycle_with_initial < S : CycleCollectionWithInitial < 'a > > (& self , on : & S :: Location , initial : S ,) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , initial , on . id ()) ,) } } } pub use builder :: FlowBuilder ; pub mod ir { pub use core :: panic ; pub use std :: cell :: RefCell ; pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow_lang :: graph :: FlatGraphBuilder ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: ToTokens ; pub use syn :: parse_quote ; pub use crate :: deploy :: Deploy ; pub use crate :: location :: LocationId ; pub use crate :: ir :: DebugExpr ; # [cfg (stageleft_macro)] impl From < syn :: Expr > for DebugExpr { fn from (expr : syn :: Expr) -> DebugExpr { DebugExpr (expr) } } # [cfg (stageleft_macro)] impl Deref for DebugExpr { type Target = syn :: Expr ; fn deref (& self) -> & Self :: Target { & self . 0 } } # [cfg (stageleft_macro)] impl ToTokens for DebugExpr { fn to_tokens (& self , tokens : & mut TokenStream) { self . 0 . to_tokens (tokens) ; } } # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugExpr { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "{}" , self . 0 . to_token_stream ()) } } pub use crate :: ir :: DebugInstantiate ; # [cfg (stageleft_macro)] impl < 'a > std :: fmt :: Debug for DebugInstantiate < 'a > { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<network instantiate>") } } pub use crate :: ir :: DebugPipelineFn ; # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugPipelineFn { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<function>") } } pub use crate :: ir :: HfPlusSource ; pub use crate :: ir :: HfPlusLeaf ; # [cfg (stageleft_macro)] impl < 'a > HfPlusLeaf < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . compile_network :: < D > (compile_env , s , nodes , clusters) ; } , seen_tees ,) } pub fn connect_network (self , seen_tees : & mut SeenTees < 'a >) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . connect_network (s) ; } , seen_tees ,) } pub fn transform_children (self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) -> HfPlusLeaf < 'a > { match self { HfPlusLeaf :: ForEach { f , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: ForEach { f , input } } HfPlusLeaf :: DestSink { sink , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: DestSink { sink , input } } HfPlusLeaf :: CycleSink { ident , location_kind , mut input , } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: CycleSink { ident , location_kind , input , } } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) { match self { HfPlusLeaf :: ForEach { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> for_each (# f) ; }) ; } HfPlusLeaf :: DestSink { sink , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink) ; }) ; } HfPlusLeaf :: CycleSink { ident , location_kind , input , } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; assert_eq ! (input_location_id , * location_id , "cycle_sink location mismatch") ; graph_builders . entry (* location_id) . or_default () . add_statement (parse_quote ! { # ident = # input_ident ; }) ; } } } } pub use crate :: ir :: HfPlusNode ; pub type SeenTees < 'a > = HashMap < * const RefCell < HfPlusNode < 'a > > , Rc < RefCell < HfPlusNode < 'a > > > > ; # [cfg (stageleft_macro)] impl < 'a > HfPlusNode < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (& mut self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) { self . transform_children (| n , s | n . compile_network :: < D > (compile_env , s , nodes , clusters) , seen_tees ,) ; if let HfPlusNode :: Network { from_location , to_location , instantiate_fn , .. } = self { let (sink_expr , source_expr , connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { let ((sink , source) , connect_fn) = match (from_location , to_location) { (LocationId :: Process (from) , LocationId :: Process (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: o2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Process (from) , LocationId :: Cluster (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: o2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Process (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: m2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Cluster (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: m2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } } ; (sink , source , connect_fn) } DebugInstantiate :: Finalized (_ , _ , _) => panic ! ("network already finalized") , } ; * instantiate_fn = DebugInstantiate :: Finalized (sink_expr , source_expr , connect_fn) ; } } pub fn connect_network (& mut self , seen_tees : & mut SeenTees < 'a >) { self . transform_children (| n , s | n . connect_network (s) , seen_tees) ; if let HfPlusNode :: Network { instantiate_fn , .. } = self { match instantiate_fn { DebugInstantiate :: Building () => panic ! ("network not built") , DebugInstantiate :: Finalized (_ , _ , ref connect_fn) => { connect_fn () ; } } } } pub fn transform_children (& mut self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) { match self { HfPlusNode :: Placeholder => { panic ! () ; } HfPlusNode :: Source { .. } => { } HfPlusNode :: CycleSource { .. } => { } HfPlusNode :: Tee { inner } => { if let Some (transformed) = seen_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { * inner = transformed . clone () ; } else { let transformed_cell = Rc :: new (RefCell :: new (HfPlusNode :: Placeholder)) ; seen_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , transformed_cell . clone () ,) ; let mut orig = inner . replace (HfPlusNode :: Placeholder) ; transform (& mut orig , seen_tees) ; * transformed_cell . borrow_mut () = orig ; * inner = transformed_cell ; } } HfPlusNode :: Persist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Unpersist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Delta (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Union (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossProduct (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossSingleton (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Join (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Difference (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: AntiJoin (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Map { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FlatMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Filter { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FilterMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Sort (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: DeferTick (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Enumerate (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Inspect { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Unique (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Fold { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FoldKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Reduce { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: ReduceKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Network { input , .. } => { transform (input . as_mut () , seen_tees) ; } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) -> (syn :: Ident , usize) { match self { HfPlusNode :: Placeholder => { panic ! () } HfPlusNode :: Persist (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let persist_id = * next_stmt_id ; * next_stmt_id += 1 ; let persist_ident = syn :: Ident :: new (& format ! ("stream_{}" , persist_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # persist_ident = # inner_ident -> persist ::<'static > () ; }) ; (persist_ident , location) } HfPlusNode :: Unpersist (_) => { panic ! ("Unpersist is a marker node and should have been optimized away. This is likely a compiler bug.") } HfPlusNode :: Delta (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let delta_id = * next_stmt_id ; * next_stmt_id += 1 ; let delta_ident = syn :: Ident :: new (& format ! ("stream_{}" , delta_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # delta_ident = # inner_ident -> multiset_delta () ; }) ; (delta_ident , location) } HfPlusNode :: Source { source , location_kind , } => { let source_id = * next_stmt_id ; * next_stmt_id += 1 ; let source_ident = syn :: Ident :: new (& format ! ("stream_{}" , source_id) , Span :: call_site ()) ; let source_stmt = match source { HfPlusSource :: Stream (expr) => { parse_quote ! { # source_ident = source_stream (# expr) ; } } HfPlusSource :: Iter (expr) => { parse_quote ! { # source_ident = source_iter (# expr) ; } } HfPlusSource :: Interval (expr) => { parse_quote ! { # source_ident = source_interval (# expr) ; } } HfPlusSource :: Spin () => { parse_quote ! { # source_ident = spin () ; } } } ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; graph_builders . entry (* location_id) . or_default () . add_statement (source_stmt) ; (source_ident , * location_id) } HfPlusNode :: CycleSource { ident , location_kind , } => { let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; (ident . clone () , * location_id) } HfPlusNode :: Tee { inner } => { if let Some (ret) = built_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { ret . clone () } else { let (inner_ident , inner_location_id) = inner . borrow () . emit (graph_builders , built_tees , next_stmt_id) ; let tee_id = * next_stmt_id ; * next_stmt_id += 1 ; let tee_ident = syn :: Ident :: new (& format ! ("stream_{}" , tee_id) , Span :: call_site ()) ; let builder = graph_builders . entry (inner_location_id) . or_default () ; builder . add_statement (parse_quote ! { # tee_ident = # inner_ident -> tee () ; }) ; built_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , (tee_ident . clone () , inner_location_id) ,) ; (tee_ident , inner_location_id) } } HfPlusNode :: Union (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "union inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let union_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # union_ident = union () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [0] # union_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # union_ident ; }) ; (union_ident , left_location_id) } HfPlusNode :: CrossSingleton (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "cross_singleton inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let cross_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # cross_ident = cross_singleton () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [input] # cross_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [single] # cross_ident ; }) ; (cross_ident , left_location_id) } HfPlusNode :: CrossProduct (..) | HfPlusNode :: Join (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: CrossProduct (..)) { parse_quote ! (cross_join_multiset) } else { parse_quote ! (join_multiset) } ; let (HfPlusNode :: CrossProduct (left , right) | HfPlusNode :: Join (left , right)) = self else { unreachable ! () } ; let (left_inner , left_was_persist) = if let HfPlusNode :: Persist (left) = left . as_ref () { (left , true) } else { (left , false) } ; let (right_inner , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left_inner . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right_inner . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "join / cross product inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; match (left_was_persist , right_was_persist) { (true , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'static > () ; }) ; } (true , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'tick > () ; }) ; } (false , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } (false , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } } ; builder . add_statement (parse_quote ! { # left_ident -> [0] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Difference (..) | HfPlusNode :: AntiJoin (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Difference (..)) { parse_quote ! (difference_multiset) } else { parse_quote ! (anti_join_multiset) } ; let (HfPlusNode :: Difference (left , right) | HfPlusNode :: AntiJoin (left , right)) = self else { unreachable ! () } ; let (right , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "difference / anti join inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; if right_was_persist { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } else { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } builder . add_statement (parse_quote ! { # left_ident -> [pos] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [neg] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Map { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let map_id = * next_stmt_id ; * next_stmt_id += 1 ; let map_ident = syn :: Ident :: new (& format ! ("stream_{}" , map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # map_ident = # input_ident -> map (# f) ; }) ; (map_ident , input_location_id) } HfPlusNode :: FlatMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let flat_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let flat_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , flat_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # flat_map_ident = # input_ident -> flat_map (# f) ; }) ; (flat_map_ident , input_location_id) } HfPlusNode :: Filter { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_ident = # input_ident -> filter (# f) ; }) ; (filter_ident , input_location_id) } HfPlusNode :: FilterMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_map_ident = # input_ident -> filter_map (# f) ; }) ; (filter_map_ident , input_location_id) } HfPlusNode :: Sort (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sort_id = * next_stmt_id ; * next_stmt_id += 1 ; let sort_ident = syn :: Ident :: new (& format ! ("stream_{}" , sort_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # sort_ident = # input_ident -> sort () ; }) ; (sort_ident , input_location_id) } HfPlusNode :: DeferTick (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let defer_tick_id = * next_stmt_id ; * next_stmt_id += 1 ; let defer_tick_ident = syn :: Ident :: new (& format ! ("stream_{}" , defer_tick_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # defer_tick_ident = # input_ident -> defer_tick_lazy () ; }) ; (defer_tick_ident , input_location_id) } HfPlusNode :: Enumerate (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let enumerate_id = * next_stmt_id ; * next_stmt_id += 1 ; let enumerate_ident = syn :: Ident :: new (& format ! ("stream_{}" , enumerate_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # enumerate_ident = # input_ident -> enumerate () ; }) ; (enumerate_ident , input_location_id) } HfPlusNode :: Inspect { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let inspect_id = * next_stmt_id ; * next_stmt_id += 1 ; let inspect_ident = syn :: Ident :: new (& format ! ("stream_{}" , inspect_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # inspect_ident = # input_ident -> inspect (# f) ; }) ; (inspect_ident , input_location_id) } HfPlusNode :: Unique (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let unique_id = * next_stmt_id ; * next_stmt_id += 1 ; let unique_ident = syn :: Ident :: new (& format ! ("stream_{}" , unique_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # unique_ident = # input_ident -> unique ::<'tick > () ; }) ; (unique_ident , input_location_id) } HfPlusNode :: Fold { .. } | HfPlusNode :: FoldKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Fold { .. }) { parse_quote ! (fold) } else { parse_quote ! (fold_keyed) } ; let (HfPlusNode :: Fold { init , acc , input } | HfPlusNode :: FoldKeyed { init , acc , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let fold_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'static > (# init , # acc) ; }) ; } else { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'tick > (# init , # acc) ; }) ; } (fold_ident , input_location_id) } HfPlusNode :: Reduce { .. } | HfPlusNode :: ReduceKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Reduce { .. }) { parse_quote ! (reduce) } else { parse_quote ! (reduce_keyed) } ; let (HfPlusNode :: Reduce { f , input } | HfPlusNode :: ReduceKeyed { f , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let reduce_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'static > (# f) ; }) ; } else { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'tick > (# f) ; }) ; } (reduce_ident , input_location_id) } HfPlusNode :: Network { from_location : _ , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input , } => { let (sink_expr , source_expr , _connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { panic ! ("Expected the network to be finalized") } DebugInstantiate :: Finalized (sink , source , connect_fn) => { (sink , source , connect_fn) } } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sender_builder = graph_builders . entry (input_location_id) . or_default () ; if let Some (serialize_pipeline) = serialize_pipeline { sender_builder . add_statement (parse_quote ! { # input_ident -> # serialize_pipeline -> dest_sink (# sink_expr) ; }) ; } else { sender_builder . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink_expr) ; }) ; } let to_id = match to_location { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let receiver_builder = graph_builders . entry (* to_id) . or_default () ; let receiver_stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let receiver_stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , receiver_stream_id) , Span :: call_site ()) ; if let Some (deserialize_pipeline) = deserialize_pipeline { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) -> # deserialize_pipeline ; }) ; } else { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) ; }) ; } (receiver_stream_ident , * to_id) } } } } } pub mod persist_pullup { pub use std :: cell :: RefCell ; pub use std :: collections :: HashSet ; pub use std :: ops :: Deref ; pub use crate :: ir :: * ; pub fn persist_pullup_node < 'a > (node : & mut HfPlusNode < 'a > , seen_tees : & mut SeenTees < 'a > , persist_pulled_tees : & mut HashSet < * const RefCell < HfPlusNode < 'a > > > ,) { node . transform_children (| n , s | persist_pullup_node (n , s , persist_pulled_tees) , seen_tees ,) ; match node { HfPlusNode :: Unpersist (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Unpersist (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Delta (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Delta (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Tee { inner } => { if persist_pulled_tees . contains (& (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >)) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } else { let inner_borrow = inner . borrow () ; if let HfPlusNode :: Persist (_) = inner_borrow . deref () { drop (inner_borrow) ; persist_pulled_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >) ; if let HfPlusNode :: Persist (box behind_persist) = inner . replace (HfPlusNode :: Placeholder) { * inner . borrow_mut () = behind_persist ; } else { unreachable ! () } * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } } } HfPlusNode :: Map { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Map { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Map { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: FlatMap { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: FlatMap { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: FlatMap { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Filter { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Filter { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Filter { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Network { input : box HfPlusNode :: Persist (_) , .. } => { if let HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Union (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Union (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Union (left , right))) ; } else { unreachable ! () } } HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: CrossProduct (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,) ,)))) ; } else { unreachable ! () } } HfPlusNode :: Join (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Join (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: Join (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,))))) ; } else { unreachable ! () } } _ => { } } } pub fn persist_pullup (ir : Vec < HfPlusLeaf >) -> Vec < HfPlusLeaf > { let mut seen_tees = Default :: default () ; let mut persist_pulled_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| n , s | persist_pullup_node (n , s , & mut persist_pulled_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn persist_pullup_through_map () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } # [test] fn persist_pullup_behind_tee () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; let before_tee = flow . source_iter (& process , q ! (0 .. 10)) . tick_batch () . persist () ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } } } pub mod profiler { pub use std :: cell :: RefCell ; pub use hydroflow :: futures :: channel :: mpsc :: UnboundedSender ; pub use stageleft :: * ; pub use crate as hydroflow_plus ; pub use crate :: ir :: * ; pub use crate :: RuntimeContext ; pub fn increment_counter (count : & mut u64) { * count += 1 ; } pub fn quoted_any_fn < 'a , F : Fn (& usize) + 'a , Q : IntoQuotedMut < 'a , F > > (q : Q) -> Q { q } # [doc = " Add a profiling node before each node to count the cardinality of its input"] pub fn add_profiling_node < 'a > (node : & mut HfPlusNode < 'a > , _context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > , id : & mut u32 , seen_tees : & mut SeenTees < 'a > ,) { let my_id = * id ; * id += 1 ; node . transform_children (| node , seen_tees | { add_profiling_node (node , _context , counters , counter_queue , id , seen_tees) } , seen_tees ,) ; let orig_node = std :: mem :: replace (node , HfPlusNode :: Placeholder) ; * node = HfPlusNode :: Inspect { f : quoted_any_fn (q ! ({ counter_queue . borrow () . unbounded_send ((my_id as usize , counters . borrow () [my_id as usize])) . unwrap () ; counters . borrow_mut () [my_id as usize] = 0 ; move | _ | { hydroflow_plus :: profiler :: increment_counter (& mut counters . borrow_mut () [my_id as usize] ,) ; } })) . splice () . into () , input : Box :: new (orig_node) , } } # [doc = " Count the cardinality of each input and periodically output to a file"] pub fn profiling < 'a > (ir : Vec < HfPlusLeaf < 'a > > , context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > ,) -> Vec < HfPlusLeaf < 'a > > { let mut id = 0 ; let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | { add_profiling_node (node , context , counters , counter_queue , & mut id , seen_tees) } , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn profiler_wrapping_all_operators () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let runtime_context = flow . runtime_context () ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (& built . ir ()) ; let counters = RuntimeData :: new ("Fake") ; let counter_queue = RuntimeData :: new ("Fake") ; let pushed_down = built . with_default_optimize () . optimize_with (| ir | super :: profiling (ir , runtime_context , counters , counter_queue)) ; insta :: assert_debug_snapshot ! (& pushed_down . ir ()) ; let _ = pushed_down . compile_no_network :: < MultiGraph > () ; } } } pub mod properties { pub use std :: collections :: HashSet ; pub use stageleft :: * ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , SeenTees } ; pub use crate :: properties :: PropertyDatabase ; # [doc = " Allows us to convert the hydroflow datatype for folds to a binary operation for the algebra"] # [doc = " property tests."] # [allow (dead_code)] pub fn convert_hf_to_binary < I , A : Default , F : Fn (& mut A , I) > (f : F) -> impl Fn (I , I) -> A { move | a , b | { let mut acc = Default :: default () ; f (& mut acc , a) ; f (& mut acc , b) ; acc } } # [cfg (stageleft_macro)] impl PropertyDatabase { # [doc = " Tags the expression as commutative."] pub fn add_commutative_tag < 'a , I , A , F : Fn (& mut A , I) , Q : Quoted < 'a , F > + Clone > (& mut self , expr : Q ,) -> Q { let expr_clone = expr . clone () ; self . commutative . insert (expr_clone . splice ()) ; expr } pub fn is_tagged_commutative (& self , expr : & syn :: Expr) -> bool { self . commutative . contains (expr) } } pub fn properties_optimize_node < 'a > (node : & mut HfPlusNode < 'a > , db : & PropertyDatabase , seen_tees : & mut SeenTees < 'a > ,) { node . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , seen_tees ,) ; match node { HfPlusNode :: ReduceKeyed { f , .. } if db . is_tagged_commutative (& f . 0) => { dbg ! ("IDENTIFIED COMMUTATIVE OPTIMIZATION for {:?}" , & f) ; } _ => { } } } pub fn properties_optimize < 'a > (ir : Vec < HfPlusLeaf < 'a > > , db : & PropertyDatabase ,) -> Vec < HfPlusLeaf < 'a > > { let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use super :: * ; use crate :: deploy :: SingleProcessGraph ; use crate :: FlowBuilder ; # [test] fn test_property_database () { let mut db = PropertyDatabase :: default () ; assert ! (! db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; let _ = db . add_commutative_tag (q ! (| a : & mut i32 , b : i32 | * a += b)) ; assert ! (db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; } # [test] fn test_property_optimized () { let flow = FlowBuilder :: new () ; let mut database = PropertyDatabase :: default () ; let process = flow . process :: < () > () ; let counter_func = q ! (| count : & mut i32 , _ | * count += 1) ; let _ = database . add_commutative_tag (counter_func) ; flow . source_iter (& process , q ! (vec ! [])) . map (q ! (| string : String | (string , ()))) . tick_batch () . fold_keyed (q ! (|| 0) , counter_func) . all_ticks () . for_each (q ! (| (string , count) | println ! ("{}: {}" , string , count))) ; let built = flow . finalize () . optimize_with (| ir | properties_optimize (ir , & database)) . with_default_optimize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let _ = built . compile_no_network :: < SingleProcessGraph > () ; } } } pub use crate :: RuntimeContext ; # [cfg (stageleft_macro)] impl Copy for RuntimeContext < '_ > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Context > for RuntimeContext < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (quote ! (& context))) } } pub use crate :: HfCompiled ; # [cfg (stageleft_macro)] impl < 'a , ID > HfCompiled < 'a , ID > { pub fn hydroflow_ir (& self) -> & BTreeMap < usize , HydroflowGraph > { & self . hydroflow_ir } } # [cfg (stageleft_macro)] impl < 'a > HfCompiled < 'a , usize > { pub fn with_dynamic_id (self , id : impl Quoted < 'a , usize >) -> HfBuiltWithId < 'a > { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; let mut conditioned_tokens = None ; for (subgraph_id , flat_graph) in self . hydroflow_ir { let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; let my_extra_stmts = self . extra_stmts . get (& subgraph_id) . cloned () . unwrap_or_default () ; if let Some (conditioned_tokens) = conditioned_tokens . as_mut () { * conditioned_tokens = syn :: parse_quote ! { # conditioned_tokens else if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } } ; } else { conditioned_tokens = Some (syn :: parse_quote ! { if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } }) ; } } let conditioned_tokens : TokenStream = conditioned_tokens . unwrap () ; let id = id . splice () ; HfBuiltWithId { tokens : syn :: parse_quote ! ({ let __given_id = # id ; # conditioned_tokens else { panic ! ("Invalid node id: {}" , __given_id) ; } }) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfCompiled < 'a , () > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfCompiled < 'a , () > { fn to_tokens (mut self) -> (Option < TokenStream > , Option < TokenStream >) { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; if self . hydroflow_ir . len () != 1 { panic ! ("Expected exactly one subgraph in the Hydroflow IR") ; } let flat_graph = self . hydroflow_ir . remove (& 0) . unwrap () ; let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; (None , Some (tokens)) } } pub use crate :: HfBuiltWithId ; # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfBuiltWithId < 'a > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfBuiltWithId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (self . tokens)) } }
[INFO] [stdout] 1 + pub use std :: collections :: BTreeMap ; pub use std :: marker :: PhantomData ; pub use hydroflow :: scheduled :: context :: Context ; pub use hydroflow :: scheduled :: graph :: Hydroflow ; pub use hydroflow :: * ; pub use lang :: graph :: { partition_graph , HydroflowGraph } ; pub use proc_macro2 :: TokenStream ; pub use quote :: quote ; pub use stageleft :: runtime_support :: FreeVariable ; pub use stageleft :: Quoted ; pub mod runtime_support { pub use bincode ; } pub mod stream { pub use std :: cell :: RefCell ; pub use std :: hash :: Hash ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow :: bytes :: Bytes ; pub use hydroflow :: futures :: Sink ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: quote ; pub use serde :: de :: DeserializeOwned ; pub use serde :: Serialize ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use syn :: parse_quote ; pub use crate :: builder :: { ClusterIds , FlowLeaves } ; pub use crate :: cycle :: { CycleCollection , CycleComplete } ; pub use crate :: ir :: { DebugInstantiate , HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { CanSend , Location , LocationId } ; pub use crate :: { Cluster , Optional , Singleton } ; pub use crate :: stream :: Unbounded ; pub use crate :: stream :: Bounded ; pub use crate :: stream :: NoTick ; pub use crate :: stream :: Tick ; pub use crate :: stream :: Stream ; # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Stream < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Stream < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Stream :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Stream { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Stream < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Stream { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Stream < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , C , N > > ,) -> Stream < 'a , (T , O) , W , C , N > where O : Clone , { let other : Optional < 'a , O , Bounded , C , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn cross_product < O > (self , other : Stream < 'a , O , W , C , N >) -> Stream < 'a , (T , O) , W , C , N > where T : Clone , O : Clone , { if self . location_kind != other . location_kind { panic ! ("cross_product must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossProduct (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn union (self , other : Stream < 'a , T , W , C , N >) -> Stream < 'a , T , W , C , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn dest_sink < S : Unpin + Sink < T > + 'a > (self , sink : impl Quoted < 'a , S >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: DestSink { sink : sink . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn first (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } # [doc = " Allow this stream through if the other stream has elements, otherwise the output is empty."] pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } # [doc = " Allow this stream through if the other stream is empty, otherwise the output is empty."] pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Stream < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn enumerate (self) -> Stream < 'a , (usize , T) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Enumerate (Box :: new (self . ir_node . into_inner ())) ,) } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn sort (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Ord , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Sort (Box :: new (self . ir_node . into_inner ())) ,) } pub fn count (self) -> Singleton < 'a , usize , Bounded , Tick , N > { self . fold (q ! (|| 0usize) , q ! (| count , _ | * count += 1)) } pub fn delta (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } pub fn unique (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Eq + Hash , { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unique (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn tick_batch (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_prefix (self) -> Stream < 'a , T , Bounded , Tick , N > where T : Clone , { self . tick_batch () . persist () } pub fn inspect < F : Fn (& T) + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , T , W , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Inspect { f : f . splice () . into () , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn for_each < F : Fn (T) + 'a > (self , f : impl IntoQuotedMut < 'a , F >) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: ForEach { input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , f : f . splice () . into () , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Stream < 'a , T , Unbounded , NoTick , N > { pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . tick_batch () . continue_if (samples . first ()) . all_ticks () } pub fn fold < A , I : Fn () -> A + 'a , F : Fn (& mut A , T) > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , A , Unbounded , NoTick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Fold { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } pub fn reduce < F : Fn (& mut T , T) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Reduce { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , C , N : Location > Stream < 'a , T , Bounded , C , N > { pub fn filter_not_in (self , other : Stream < 'a , T , Bounded , C , N >) -> Stream < 'a , T , Bounded , C , N > where T : Eq + Hash , { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Difference (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Stream < 'a , & T , W , C , N > { pub fn cloned (self) -> Stream < 'a , T , W , C , N > { self . map (q ! (| d | d . clone ())) } } # [cfg (stageleft_macro)] impl < 'a , K , V1 , W , C , N : Location > Stream < 'a , (K , V1) , W , C , N > { pub fn join < W2 , V2 > (self , n : Stream < 'a , (K , V2) , W2 , C , N > ,) -> Stream < 'a , (K , (V1 , V2)) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Join (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } pub fn anti_join < W2 > (self , n : Stream < 'a , K , W2 , C , N >) -> Stream < 'a , (K , V1) , W , C , N > where K : Eq + Hash , { if self . location_kind != n . location_kind { panic ! ("anti_join must be called on streams on the same node") ; } Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: AntiJoin (Box :: new (self . ir_node . into_inner ()) , Box :: new (n . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , K : Eq + Hash , V , N : Location > Stream < 'a , (K , V) , Bounded , Tick , N > { pub fn fold_keyed < A , I : Fn () -> A + 'a , F : Fn (& mut A , V) + 'a > (self , init : impl IntoQuotedMut < 'a , I > , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , A) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FoldKeyed { init : init . splice () . into () , acc : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn reduce_keyed < F : Fn (& mut V , V) + 'a > (self , comb : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , (K , V) , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: ReduceKeyed { f : comb . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } pub fn get_this_crate () -> TokenStream { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , Span :: call_site ()) ; quote ! { # ident } } } } pub fn serialize_bincode < T : Serialize > (is_demux : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if is_demux { parse_quote ! { map (| (id , data) | { (id , # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into ()) }) } } else { parse_quote ! { map (| data | { # root :: runtime_support :: bincode :: serialize ::<# t_type > (& data) . unwrap () . into () }) } } } pub fn deserialize_bincode < T : DeserializeOwned > (tagged : bool) -> Pipeline { let root = get_this_crate () ; let t_type : syn :: Type = stageleft :: quote_type :: < T > () ; if tagged { parse_quote ! { map (| res | { let (id , b) = res . unwrap () ; (id , # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& b) . unwrap ()) }) } } else { parse_quote ! { map (| res | { # root :: runtime_support :: bincode :: deserialize ::<# t_type > (& res . unwrap ()) . unwrap () }) } } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > Stream < 'a , T , W , NoTick , N > { pub fn send_bincode < N2 : Location , CoreType > (self , other : & N2 ,) -> Stream < 'a , N :: Out < CoreType > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T > , CoreType : Serialize + DeserializeOwned , { let serialize_pipeline = Some (serialize_bincode :: < CoreType > (N :: is_demux ())) ; let deserialize_pipeline = Some (deserialize_bincode :: < CoreType > (N :: is_tagged ())) ; Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bytes < N2 : Location > (self , other : & N2 ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T > , { Stream :: new (other . id () , self . ir_leaves , HfPlusNode :: Network { from_location : self . location_kind , to_location : other . id () , serialize_pipeline : None , instantiate_fn : DebugInstantiate :: Building () , deserialize_pipeline : if N :: is_tagged () { Some (parse_quote ! (map (| (id , b) | (id , b . unwrap () . freeze ())))) } else { Some (parse_quote ! (map (| b | b . unwrap () . freeze ()))) } , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn send_bincode_interleaved < N2 : Location , Tag , CoreType > (self , other : & N2 ,) -> Stream < 'a , CoreType , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < CoreType > = T , Out < CoreType > = (Tag , CoreType) > , CoreType : Serialize + DeserializeOwned , { self . send_bincode :: < N2 , CoreType > (other) . map (q ! (| (_ , b) | b)) } pub fn send_bytes_interleaved < N2 : Location , Tag > (self , other : & N2 ,) -> Stream < 'a , Bytes , Unbounded , NoTick , N2 > where N : CanSend < N2 , In < Bytes > = T , Out < Bytes > = (Tag , Bytes) > , { self . send_bytes :: < N2 > (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bincode < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < T > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) > , T : Clone + Serialize + DeserializeOwned , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bincode (other) } pub fn broadcast_bincode_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , T , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < T > = (u32 , T) , Out < T > = (Tag , T) > + 'a , T : Clone + Serialize + DeserializeOwned , { self . broadcast_bincode (other) . map (q ! (| (_ , b) | b)) } pub fn broadcast_bytes < C2 > (self , other : & Cluster < C2 > ,) -> Stream < 'a , N :: Out < Bytes > , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) > + 'a , T : Clone , { let ids = ClusterIds :: < 'a > { id : other . id , _phantom : PhantomData , } ; self . flat_map (q ! (| b | ids . iter () . map (move | id | (:: std :: clone :: Clone :: clone (id) , :: std :: clone :: Clone :: clone (& b))))) . send_bytes (other) } pub fn broadcast_bytes_interleaved < C2 , Tag > (self , other : & Cluster < C2 > ,) -> Stream < 'a , Bytes , Unbounded , NoTick , Cluster < C2 > > where N : CanSend < Cluster < C2 > , In < Bytes > = (u32 , T) , Out < Bytes > = (Tag , Bytes) > + 'a , T : Clone , { self . broadcast_bytes (other) . map (q ! (| (_ , b) | b)) } } } pub use stream :: { Bounded , NoTick , Stream , Tick , Unbounded } ; pub mod singleton { pub use std :: cell :: RefCell ; pub use std :: marker :: PhantomData ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use stageleft :: { q , IntoQuotedMut , Quoted } ; pub use crate :: builder :: FlowLeaves ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial , CycleComplete } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: Stream ; pub use crate :: singleton :: CrossResult ; # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Singleton < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Singleton :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Singleton < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Optional < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Optional < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Optional < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } # [cfg (stageleft_macro)] impl < 'a , T , U : Clone , W , C , N : Location > CrossResult < 'a , Singleton < 'a , U , W , C , N > > for Optional < 'a , T , W , C , N > { type Out = Optional < 'a , (T , U) , W , C , N > ; fn other_location (other : & Singleton < 'a , U , W , C , N >) -> LocationId { other . location_kind } fn other_ir_node (other : Singleton < 'a , U , W , C , N >) -> HfPlusNode < 'a > { other . ir_node . into_inner () } fn make (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self :: Out { Optional :: new (location_kind , ir_leaves , ir_node) } } pub use crate :: singleton :: Singleton ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Singleton { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleComplete < 'a > for Singleton < 'a , T , Bounded , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > CycleCollectionWithInitial < 'a > for Singleton < 'a , T , Bounded , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , initial : Self , l : LocationId ,) -> Self { Singleton :: new (l , ir_leaves , HfPlusNode :: Union (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , }) , initial . ir_node . into_inner () . into () ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Singleton < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Singleton { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Singleton < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Singleton < 'a , U , W , C , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (Self :: other_ir_node (other)) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Singleton < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Singleton < 'a , T , Bounded , Tick , N > { Singleton :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Singleton < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < Other > (self , other : Other) -> < Self as CrossResult < 'a , Other > > :: Out where Self : CrossResult < 'a , Other > , { if self . location_kind != Self :: other_location (& other) { panic ! ("cross_singleton must be called on streams on the same node") ; } Self :: make (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CrossSingleton (Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , Box :: new (HfPlusNode :: Unpersist (Box :: new (Self :: other_ir_node (other)))) ,))) ,) } } pub use crate :: singleton :: Optional ; # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub (crate) fn new (location_kind : LocationId , ir_leaves : FlowLeaves < 'a > , ir_node : HfPlusNode < 'a > ,) -> Self { Optional { location_kind , ir_leaves , ir_node : RefCell :: new (ir_node) , _phantom : PhantomData , } } pub fn some (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: new (singleton . location_kind , singleton . ir_leaves , singleton . ir_node . into_inner () ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , Tick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (self . ir_node . into_inner ()) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , Tick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: CycleSource { ident , location_kind : l , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleComplete < 'a > for Optional < 'a , T , W , NoTick , N > { fn complete (self , ident : syn :: Ident) { self . ir_leaves . borrow_mut () . as_mut () . expect ("Attempted to add a leaf to a flow that has already been finalized. No leaves can be added after the flow has been compiled.") . push (HfPlusLeaf :: CycleSink { ident , location_kind : self . location_kind , input : Box :: new (HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ()))) , }) ; } } # [cfg (stageleft_macro)] impl < 'a , T , W , N : Location > CycleCollection < 'a > for Optional < 'a , T , W , NoTick , N > { type Location = N ; fn create_source (ident : syn :: Ident , ir_leaves : FlowLeaves < 'a > , l : LocationId) -> Self { Optional :: new (l , ir_leaves , HfPlusNode :: Persist (Box :: new (HfPlusNode :: CycleSource { ident , location_kind : l , })) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > From < Singleton < 'a , T , W , C , N > > for Optional < 'a , T , W , C , N > { fn from (singleton : Singleton < 'a , T , W , C , N >) -> Self { Optional :: some (singleton) } } # [cfg (stageleft_macro)] impl < 'a , T : Clone , W , C , N : Location > Clone for Optional < 'a , T , W , C , N > { fn clone (& self) -> Self { if ! matches ! (self . ir_node . borrow () . deref () , HfPlusNode :: Tee { .. }) { let orig_ir_node = self . ir_node . replace (HfPlusNode :: Placeholder) ; * self . ir_node . borrow_mut () = HfPlusNode :: Tee { inner : Rc :: new (RefCell :: new (orig_ir_node)) , } ; } if let HfPlusNode :: Tee { inner } = self . ir_node . borrow () . deref () { Optional { location_kind : self . location_kind , ir_leaves : self . ir_leaves . clone () , ir_node : HfPlusNode :: Tee { inner : inner . clone () , } . into () , _phantom : PhantomData , } } else { unreachable ! () } } } # [cfg (stageleft_macro)] impl < 'a , T , W , C , N : Location > Optional < 'a , T , W , C , N > { pub fn map < U , F : Fn (T) -> U + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Map { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn flat_map < U , I : IntoIterator < Item = U > , F : Fn (T) -> I + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Stream < 'a , U , W , C , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FlatMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter < F : Fn (& T) -> bool + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , T , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Filter { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } pub fn filter_map < U , F : Fn (T) -> Option < U > + 'a > (self , f : impl IntoQuotedMut < 'a , F > ,) -> Optional < 'a , U , W , C , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: FilterMap { f : f . splice () . into () , input : Box :: new (self . ir_node . into_inner ()) , } ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn into_stream (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , self . ir_node . into_inner () ,) } pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Bounded , Tick , N > > ,) -> Optional < 'a , (T , O) , Bounded , Tick , N > where O : Clone , { let other : Optional < 'a , O , Bounded , Tick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: CrossSingleton (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } pub fn continue_if < U > (self , signal : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . cross_singleton (signal . map (q ! (| _u | ()))) . map (q ! (| (d , _signal) | d)) } pub fn continue_unless < U > (self , other : Optional < 'a , U , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { self . continue_if (other . into_stream () . count () . filter (q ! (| c | * c == 0))) } pub fn union (self , other : Optional < 'a , T , Bounded , Tick , N > ,) -> Optional < 'a , T , Bounded , Tick , N > { if self . location_kind != other . location_kind { panic ! ("union must be called on streams on the same node") ; } Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Union (Box :: new (self . ir_node . into_inner ()) , Box :: new (other . ir_node . into_inner ()) ,) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Bounded , Tick , N > { pub fn all_ticks (self) -> Stream < 'a , T , Unbounded , NoTick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn latest (self) -> Optional < 'a , T , Unbounded , NoTick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn defer_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: DeferTick (Box :: new (self . ir_node . into_inner ())) ,) } pub fn persist (self) -> Stream < 'a , T , Bounded , Tick , N > { Stream :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Persist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn delta (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Delta (Box :: new (self . ir_node . into_inner ())) ,) } } # [cfg (stageleft_macro)] impl < 'a , T , B , N : Location > Optional < 'a , T , B , NoTick , N > { pub fn latest_tick (self) -> Optional < 'a , T , Bounded , Tick , N > { Optional :: new (self . location_kind , self . ir_leaves , HfPlusNode :: Unpersist (Box :: new (self . ir_node . into_inner ())) ,) } pub fn tick_samples (self) -> Stream < 'a , T , Unbounded , NoTick , N > { self . latest_tick () . all_ticks () } pub fn sample_every (self , duration : impl Quoted < 'a , std :: time :: Duration > + Copy + 'a ,) -> Stream < 'a , T , Unbounded , NoTick , N > { let interval = duration . splice () ; let samples = Stream :: < 'a , hydroflow :: tokio :: time :: Instant , Bounded , Tick , N > :: new (self . location_kind , self . ir_leaves . clone () , HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : self . location_kind , } ,) ; self . latest_tick () . continue_if (samples . first ()) . latest () . tick_samples () } } # [cfg (stageleft_macro)] impl < 'a , T , N : Location > Optional < 'a , T , Unbounded , NoTick , N > { pub fn cross_singleton < O > (self , other : impl Into < Optional < 'a , O , Unbounded , NoTick , N > > ,) -> Optional < 'a , (T , O) , Unbounded , NoTick , N > where O : Clone , { let other : Optional < 'a , O , Unbounded , NoTick , N > = other . into () ; if self . location_kind != other . location_kind { panic ! ("cross_singleton must be called on streams on the same node") ; } self . latest_tick () . cross_singleton (other . latest_tick ()) . latest () } } } pub use singleton :: { Optional , Singleton } ; pub mod location { pub use std :: marker :: PhantomData ; pub use crate :: location :: LocationId ; pub use crate :: location :: Location ; pub use crate :: location :: Process ; # [cfg (stageleft_macro)] impl < P > Clone for Process < P > { fn clone (& self) -> Self { Process { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < P > Location for Process < P > { fn id (& self) -> LocationId { LocationId :: Process (self . id) } } pub use crate :: location :: Cluster ; # [cfg (stageleft_macro)] impl < C > Clone for Cluster < C > { fn clone (& self) -> Self { Cluster { id : self . id , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < C > Location for Cluster < C > { fn id (& self) -> LocationId { LocationId :: Cluster (self . id) } } pub use crate :: location :: CanSend ; # [cfg (stageleft_macro)] impl < P1 , P2 > CanSend < Process < P2 > > for Process < P1 > { type In < T > = T ; type Out < T > = T ; fn is_demux () -> bool { false } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < P1 , C2 > CanSend < Cluster < C2 > > for Process < P1 > { type In < T > = (u32 , T) ; type Out < T > = T ; fn is_demux () -> bool { true } fn is_tagged () -> bool { false } } # [cfg (stageleft_macro)] impl < C1 , P2 > CanSend < Process < P2 > > for Cluster < C1 > { type In < T > = T ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { false } fn is_tagged () -> bool { true } } # [cfg (stageleft_macro)] impl < C1 , C2 > CanSend < Cluster < C2 > > for Cluster < C1 > { type In < T > = (u32 , T) ; type Out < T > = (u32 , T) ; fn is_demux () -> bool { true } fn is_tagged () -> bool { true } } } pub use location :: { Cluster , Process } ; pub mod deploy { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use stageleft :: Quoted ; pub mod graphs { pub use hydroflow_lang :: graph :: HydroflowGraph ; pub use super :: { LocalDeploy , Node , ProcessSpec } ; pub use crate :: deploy :: graphs :: SingleProcessGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for SingleProcessGraph { type Process = SingleNode ; type Cluster = SingleNode ; type Meta = () ; type GraphId = () ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { SingleNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { SingleNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , SingleProcessGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> SingleNode { SingleNode { } } } pub use crate :: deploy :: graphs :: SingleNode ; # [cfg (stageleft_macro)] impl Node for SingleNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } pub use crate :: deploy :: graphs :: MultiGraph ; # [cfg (stageleft_macro)] impl < 'a > LocalDeploy < 'a > for MultiGraph { type Process = MultiNode ; type Cluster = MultiNode ; type Meta = () ; type GraphId = usize ; fn has_trivial_node () -> bool { true } fn trivial_process (_id : usize) -> Self :: Process { MultiNode { } } fn trivial_cluster (_id : usize) -> Self :: Cluster { MultiNode { } } } # [cfg (stageleft_macro)] impl < 'a > ProcessSpec < 'a , MultiGraph > for () { fn build (self , _id : usize , _name_hint : & str) -> MultiNode { MultiNode { } } } pub use crate :: deploy :: graphs :: MultiNode ; # [cfg (stageleft_macro)] impl Node for MultiNode { type Port = () ; type Meta = () ; type InstantiateEnv = () ; fn next_port (& self) { panic ! () ; } fn update_meta (& mut self , _meta : & Self :: Meta) { } fn instantiate (& self , _env : & mut Self :: InstantiateEnv , _meta : & mut Self :: Meta , _graph : HydroflowGraph , _extra_stmts : Vec < syn :: Stmt > ,) { } } } pub use graphs :: * ; pub use crate :: deploy :: LocalDeploy ; pub use crate :: deploy :: Deploy ; # [cfg (stageleft_macro)] impl < 'a , T : Deploy < 'a , Process = N , Cluster = C , Meta = M , GraphId = R > , N : Node < Meta = M > , C : Node < Meta = M > , M : Default , R , > LocalDeploy < 'a > for T { type Process = N ; type Cluster = C ; type Meta = M ; type GraphId = R ; fn has_trivial_node () -> bool { < T as Deploy < 'a > > :: has_trivial_node () } fn trivial_process (id : usize) -> Self :: Process { < T as Deploy < 'a > > :: trivial_process (id) } fn trivial_cluster (id : usize) -> Self :: Cluster { < T as Deploy < 'a > > :: trivail_cluster (id) } } pub use crate :: deploy :: ProcessSpec ; pub use crate :: deploy :: ClusterSpec ; pub use crate :: deploy :: Node ; } pub use deploy :: { ClusterSpec , Deploy , ProcessSpec } ; pub mod cycle { pub use std :: marker :: PhantomData ; pub use crate :: builder :: FlowLeaves ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: cycle :: CycleComplete ; pub use crate :: cycle :: CycleCollection ; pub use crate :: cycle :: CycleCollectionWithInitial ; pub use crate :: cycle :: HfCycle ; # [cfg (stageleft_macro)] impl < 'a , S : CycleComplete < 'a > > HfCycle < 'a , S > { pub fn complete (self , stream : S) { let ident = self . ident ; S :: complete (stream , ident) } } } pub use cycle :: HfCycle ; pub mod builder { pub use std :: cell :: RefCell ; pub use std :: collections :: HashMap ; pub use std :: marker :: PhantomData ; pub use std :: rc :: Rc ; pub use std :: time :: Duration ; pub use hydroflow :: futures :: stream :: Stream as FuturesStream ; pub use hydroflow :: { tokio , tokio_stream } ; pub use internal :: TokenStream ; pub use proc_macro2 :: Span ; pub use quote :: quote ; pub use runtime_support :: FreeVariable ; pub use stageleft :: * ; pub use crate :: cycle :: { CycleCollection , CycleCollectionWithInitial } ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , HfPlusSource } ; pub use crate :: location :: { Cluster , Location , LocationId , Process } ; pub use crate :: stream :: { Bounded , NoTick , Tick , Unbounded } ; pub use crate :: { HfCycle , Optional , RuntimeContext , Singleton , Stream } ; pub mod built { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use hydroflow_lang :: graph :: { eliminate_extra_unions_tees , HydroflowGraph } ; pub use super :: deploy :: { DeployFlow , DeployResult } ; pub use crate :: deploy :: { ClusterSpec , Deploy , LocalDeploy , ProcessSpec } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Cluster , Process } ; pub use crate :: HfCompiled ; pub use crate :: builder :: built :: BuiltFlow ; # [cfg (stageleft_macro)] impl < 'a > Drop for BuiltFlow < 'a > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped BuiltFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn ir (& self) -> & Vec < HfPlusLeaf < 'a > > { & self . ir } pub fn optimize_with (mut self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> BuiltFlow < 'a > { self . used = true ; BuiltFlow { ir : f (std :: mem :: take (& mut self . ir)) , processes : std :: mem :: take (& mut self . processes) , clusters : std :: mem :: take (& mut self . clusters) , used : false , _phantom : PhantomData , } } } pub fn build_inner (ir : & mut Vec < HfPlusLeaf >) -> BTreeMap < usize , HydroflowGraph > { let mut builders = BTreeMap :: new () ; let mut built_tees = HashMap :: new () ; let mut next_stmt_id = 0 ; for leaf in ir { leaf . emit (& mut builders , & mut built_tees , & mut next_stmt_id) ; } builders . into_iter () . map (| (k , v) | { let (mut flat_graph , _ , _) = v . build () ; eliminate_extra_unions_tees (& mut flat_graph) ; (k , flat_graph) }) . collect () } # [cfg (stageleft_macro)] impl < 'a > BuiltFlow < 'a > { pub fn compile_no_network < D : LocalDeploy < 'a > > (mut self) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; HfCompiled { hydroflow_ir : build_inner (& mut self . ir) , extra_stmts : BTreeMap :: new () , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> BuiltFlow < 'a > { self . optimize_with (crate :: persist_pullup :: persist_pullup) } fn into_deploy < D : LocalDeploy < 'a > > (mut self) -> DeployFlow < 'a , D > { self . used = true ; let processes = if D :: has_trivial_node () { self . processes . iter () . map (| id | (* id , D :: trivial_process (* id))) . collect () } else { HashMap :: new () } ; let clusters = if D :: has_trivial_node () { self . clusters . iter () . map (| id | (* id , D :: trivial_cluster (* id))) . collect () } else { HashMap :: new () } ; DeployFlow { ir : std :: mem :: take (& mut self . ir) , nodes : processes , clusters , used : false , _phantom : PhantomData , } } pub fn with_process < P , D : LocalDeploy < 'a > > (self , process : & Process < P > , spec : impl ProcessSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_process (process , spec) } pub fn with_cluster < C , D : LocalDeploy < 'a > > (self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D > ,) -> DeployFlow < 'a , D > { self . into_deploy () . with_cluster (cluster , spec) } pub fn compile < D : Deploy < 'a > + 'a > (self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . into_deploy :: < D > () . compile (env) } pub fn deploy < D : Deploy < 'a , CompileEnv = () > + 'a > (self , env : & mut D :: InstantiateEnv ,) -> DeployResult < 'a , D > { self . into_deploy :: < D > () . deploy (env) } } } pub mod deploy { pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: marker :: PhantomData ; pub use proc_macro2 :: Span ; pub use stageleft :: Quoted ; pub use super :: built :: build_inner ; pub use crate :: deploy :: { LocalDeploy , Node } ; pub use crate :: ir :: HfPlusLeaf ; pub use crate :: location :: { Location , LocationId } ; pub use crate :: { Cluster , ClusterSpec , Deploy , HfCompiled , Process , ProcessSpec } ; pub use crate :: builder :: deploy :: DeployFlow ; # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > Drop for DeployFlow < 'a , D > { fn drop (& mut self) { if ! self . used { panic ! ("Dropped DeployFlow without instantiating, you may have forgotten to call `compile` or `deploy`.") ; } } } # [cfg (stageleft_macro)] impl < 'a , D : LocalDeploy < 'a > > DeployFlow < 'a , D > { pub fn with_process < P > (mut self , process : & Process < P > , spec : impl ProcessSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < P > () . to_string () ; self . nodes . insert (process . id , spec . build (process . id , & tag_name)) ; self } pub fn with_cluster < C > (mut self , cluster : & Cluster < C > , spec : impl ClusterSpec < 'a , D >) -> Self { let tag_name = std :: any :: type_name :: < C > () . to_string () ; self . clusters . insert (cluster . id , spec . build (cluster . id , & tag_name)) ; self } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployFlow < 'a , D > { pub fn compile (mut self , env : & D :: CompileEnv) -> HfCompiled < 'a , D :: GraphId > { self . used = true ; let mut seen_tees : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | leaf . compile_network :: < D > (env , & mut seen_tees , & self . nodes , & self . clusters)) . collect () ; let extra_stmts = self . extra_stmts (env) ; HfCompiled { hydroflow_ir : build_inner (& mut ir_leaves_networked) , extra_stmts , _phantom : PhantomData , } } fn extra_stmts (& self , env : & < D as Deploy < 'a > > :: CompileEnv) -> BTreeMap < usize , Vec < syn :: Stmt > > { let all_locations_count = self . nodes . len () + self . clusters . len () ; let mut extra_stmts : BTreeMap < usize , Vec < syn :: Stmt > > = BTreeMap :: new () ; for & c_id in self . clusters . keys () { let self_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , c_id) , Span :: call_site () ,) ; let self_id_expr = D :: cluster_self_id (env) . splice () ; extra_stmts . entry (c_id) . or_default () . push (syn :: parse_quote ! { let # self_id_ident = # self_id_expr ; }) ; for other_location in 0 .. all_locations_count { let other_id_ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , c_id) , Span :: call_site () ,) ; let other_id_expr = D :: cluster_ids (env , c_id) . splice () ; extra_stmts . entry (other_location) . or_default () . push (syn :: parse_quote ! { let # other_id_ident = # other_id_expr ; }) ; } } extra_stmts } } # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a , CompileEnv = () > > DeployFlow < 'a , D > { # [must_use] pub fn deploy (mut self , env : & mut D :: InstantiateEnv) -> DeployResult < 'a , D > { self . used = true ; let mut seen_tees_instantiate : HashMap < _ , _ > = HashMap :: new () ; let mut ir_leaves_networked : Vec < HfPlusLeaf > = std :: mem :: take (& mut self . ir) . into_iter () . map (| leaf | { leaf . compile_network :: < D > (& () , & mut seen_tees_instantiate , & self . nodes , & self . clusters ,) }) . collect () ; let mut compiled = build_inner (& mut ir_leaves_networked) ; let mut extra_stmts = self . extra_stmts (& ()) ; let mut meta = D :: Meta :: default () ; let (mut processes , mut clusters) = (std :: mem :: take (& mut self . nodes) . into_iter () . map (| (node_id , node) | { node . instantiate (env , & mut meta , compiled . remove (& node_id) . unwrap () , extra_stmts . remove (& node_id) . unwrap_or_default () ,) ; (node_id , node) }) . collect :: < HashMap < _ , _ > > () , std :: mem :: take (& mut self . clusters) . into_iter () . map (| (cluster_id , cluster) | { cluster . instantiate (env , & mut meta , compiled . remove (& cluster_id) . unwrap () , extra_stmts . remove (& cluster_id) . unwrap_or_default () ,) ; (cluster_id , cluster) }) . collect :: < HashMap < _ , _ > > () ,) ; for node in processes . values_mut () { node . update_meta (& meta) ; } for cluster in clusters . values_mut () { cluster . update_meta (& meta) ; } let mut seen_tees_connect = HashMap :: new () ; for leaf in ir_leaves_networked { leaf . connect_network (& mut seen_tees_connect) ; } DeployResult { processes , clusters , } } } pub use crate :: builder :: deploy :: DeployResult ; # [cfg (stageleft_macro)] impl < 'a , D : Deploy < 'a > > DeployResult < 'a , D > { pub fn get_process < P > (& self , p : & Process < P >) -> & D :: Process { let id = match p . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . processes . get (& id) . unwrap () } pub fn get_cluster < C > (& self , c : & Cluster < C >) -> & D :: Cluster { let id = match c . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; self . clusters . get (& id) . unwrap () } } } # [doc = " Tracks the leaves of the dataflow IR. This is referenced by"] # [doc = " `Stream` and `HfCycle` to build the IR. The inner option will"] # [doc = " be set to `None` when this builder is finalized."] pub type FlowLeaves < 'a > = Rc < RefCell < Option < Vec < HfPlusLeaf < 'a > > > > > ; pub use crate :: builder :: ClusterIds ; # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Vec < u32 > > for ClusterIds < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_ids_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , & 'a Vec < u32 > > for ClusterIds < 'a > { } # [derive (Copy , Clone)] pub struct ClusterSelfId < 'a > { pub id : usize , pub _phantom : PhantomData < & 'a mut & 'a u32 > , } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < u32 > for ClusterSelfId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) where Self : Sized , { let ident = syn :: Ident :: new (& format ! ("__hydroflow_plus_cluster_self_id_{}" , self . id) , Span :: call_site () ,) ; (None , Some (quote ! { # ident })) } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , u32 > for ClusterSelfId < 'a > { } pub use crate :: builder :: FlowBuilder ; # [cfg (stageleft_macro)] impl < 'a > Drop for FlowBuilder < 'a > { fn drop (& mut self) { if ! self . finalized { panic ! ("Dropped FlowBuilder without finalizing, you may have forgotten to call `with_default_optimize`, `optimize_with`, or `finalize`.") ; } } } # [cfg (stageleft_macro)] impl < 'a > QuotedContext for FlowBuilder < 'a > { fn create () -> Self { FlowBuilder :: new () } } # [cfg (stageleft_macro)] impl < 'a > FlowBuilder < 'a > { # [allow (clippy :: new_without_default)] pub fn new () -> FlowBuilder < 'a > { FlowBuilder { ir_leaves : Rc :: new (RefCell :: new (Some (Vec :: new ()))) , nodes : RefCell :: new (vec ! []) , clusters : RefCell :: new (vec ! []) , cycle_ids : RefCell :: new (HashMap :: new ()) , next_node_id : RefCell :: new (0) , finalized : false , _phantom : PhantomData , } } pub fn finalize (mut self) -> built :: BuiltFlow < 'a > { self . finalized = true ; built :: BuiltFlow { ir : self . ir_leaves . borrow_mut () . take () . unwrap () , processes : self . nodes . replace (vec ! []) , clusters : self . clusters . replace (vec ! []) , used : false , _phantom : PhantomData , } } pub fn with_default_optimize (self) -> built :: BuiltFlow < 'a > { self . finalize () . with_default_optimize () } pub fn optimize_with (self , f : impl FnOnce (Vec < HfPlusLeaf < 'a > >) -> Vec < HfPlusLeaf < 'a > > ,) -> built :: BuiltFlow < 'a > { self . finalize () . optimize_with (f) } pub fn ir_leaves (& self) -> & FlowLeaves < 'a > { & self . ir_leaves } pub fn process < P > (& self) -> Process < P > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . nodes . borrow_mut () . push (id) ; Process { id , _phantom : PhantomData , } } pub fn cluster < C > (& self) -> Cluster < C > { let mut next_node_id = self . next_node_id . borrow_mut () ; let id = * next_node_id ; * next_node_id += 1 ; self . clusters . borrow_mut () . push (id) ; Cluster { id , _phantom : PhantomData , } } pub fn runtime_context (& self) -> RuntimeContext < 'a > { RuntimeContext { _phantom : PhantomData , } } pub fn cluster_members < C > (& self , cluster : & Cluster < C > ,) -> impl Quoted < 'a , & 'a Vec < u32 > > + Copy + 'a { ClusterIds { id : cluster . id , _phantom : PhantomData , } } pub fn cluster_self_id < C > (& self , cluster : & Cluster < C >) -> impl Quoted < 'a , u32 > + Copy + 'a { ClusterSelfId { id : cluster . id , _phantom : PhantomData , } } pub fn spin < L : Location > (& self , on : & L) -> Stream < 'a , () , Unbounded , NoTick , L > { Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Spin () , location_kind : on . id () , })) ,) } pub fn spin_batch < L : Location > (& self , on : & L , batch_size : impl Quoted < 'a , usize > + Copy + 'a ,) -> Stream < 'a , () , Bounded , Tick , L > { self . spin (on) . flat_map (q ! (move | _ | 0 .. batch_size)) . map (q ! (| _ | ())) . tick_batch () } pub fn source_stream < T , E : FuturesStream < Item = T > + Unpin , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Unbounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Stream (e . into ()) , location_kind : on . id () , })) ,) } pub fn source_iter < T , E : IntoIterator < Item = T > , L : Location > (& self , on : & L , e : impl Quoted < 'a , E > ,) -> Stream < 'a , T , Bounded , NoTick , L > { let e = e . splice () ; Stream :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , })) ,) } pub fn singleton < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Singleton < 'a , T , Bounded , NoTick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Singleton :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,)))) ,) } pub fn singleton_first_tick < T : Clone , L : Location > (& self , on : & L , e : impl Quoted < 'a , T > ,) -> Optional < 'a , T , Bounded , Tick , L > { let e_arr = q ! ([e]) ; let e = e_arr . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Source { source : HfPlusSource :: Iter (e . into ()) , location_kind : on . id () , } ,) } pub fn source_interval < L : Location > (& self , on : & L , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , () , Unbounded , NoTick , L > { let interval = interval . splice () ; Optional :: new (on . id () , self . ir_leaves () . clone () , HfPlusNode :: Persist (Box :: new (HfPlusNode :: Source { source : HfPlusSource :: Interval (interval . into ()) , location_kind : on . id () , })) ,) } pub fn source_interval_delayed < L : Location > (& self , on : & L , delay : impl Quoted < 'a , Duration > + Copy + 'a , interval : impl Quoted < 'a , Duration > + Copy + 'a ,) -> Optional < 'a , tokio :: time :: Instant , Unbounded , NoTick , L > { self . source_stream (on , q ! (tokio_stream :: wrappers :: IntervalStream :: new (tokio :: time :: interval_at (tokio :: time :: Instant :: now () + delay , interval))) ,) . tick_batch () . first () . latest () } pub fn cycle < S : CycleCollection < 'a > > (& self , on : & S :: Location) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , on . id ()) ,) } pub fn cycle_with_initial < S : CycleCollectionWithInitial < 'a > > (& self , on : & S :: Location , initial : S ,) -> (HfCycle < 'a , S > , S) { let next_id = { let on_id = match on . id () { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let mut cycle_ids = self . cycle_ids . borrow_mut () ; let next_id_entry = cycle_ids . entry (on_id) . or_default () ; let id = * next_id_entry ; * next_id_entry += 1 ; id } ; let ident = syn :: Ident :: new (& format ! ("cycle_{}" , next_id) , Span :: call_site ()) ; (HfCycle { ident : ident . clone () , _phantom : PhantomData , } , S :: create_source (ident , self . ir_leaves . clone () , initial , on . id ()) ,) } } } pub use builder :: FlowBuilder ; pub mod ir { pub use core :: panic ; pub use std :: cell :: RefCell ; pub use std :: collections :: { BTreeMap , HashMap } ; pub use std :: ops :: Deref ; pub use std :: rc :: Rc ; pub use hydroflow_lang :: graph :: FlatGraphBuilder ; pub use hydroflow_lang :: parse :: Pipeline ; pub use proc_macro2 :: { Span , TokenStream } ; pub use quote :: ToTokens ; pub use syn :: parse_quote ; pub use crate :: deploy :: Deploy ; pub use crate :: location :: LocationId ; pub use crate :: ir :: DebugExpr ; # [cfg (stageleft_macro)] impl From < syn :: Expr > for DebugExpr { fn from (expr : syn :: Expr) -> DebugExpr { DebugExpr (expr) } } # [cfg (stageleft_macro)] impl Deref for DebugExpr { type Target = syn :: Expr ; fn deref (& self) -> & Self :: Target { & self . 0 } } # [cfg (stageleft_macro)] impl ToTokens for DebugExpr { fn to_tokens (& self , tokens : & mut TokenStream) { self . 0 . to_tokens (tokens) ; } } # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugExpr { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "{}" , self . 0 . to_token_stream ()) } } pub use crate :: ir :: DebugInstantiate ; # [cfg (stageleft_macro)] impl < 'a > std :: fmt :: Debug for DebugInstantiate < 'a > { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<network instantiate>") } } pub use crate :: ir :: DebugPipelineFn ; # [cfg (stageleft_macro)] impl std :: fmt :: Debug for DebugPipelineFn { fn fmt (& self , f : & mut std :: fmt :: Formatter < '_ >) -> std :: fmt :: Result { write ! (f , "<function>") } } pub use crate :: ir :: HfPlusSource ; pub use crate :: ir :: HfPlusLeaf ; # [cfg (stageleft_macro)] impl < 'a > HfPlusLeaf < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . compile_network :: < D > (compile_env , s , nodes , clusters) ; } , seen_tees ,) } pub fn connect_network (self , seen_tees : & mut SeenTees < 'a >) -> HfPlusLeaf < 'a > { self . transform_children (| n , s | { n . connect_network (s) ; } , seen_tees ,) } pub fn transform_children (self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) -> HfPlusLeaf < 'a > { match self { HfPlusLeaf :: ForEach { f , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: ForEach { f , input } } HfPlusLeaf :: DestSink { sink , mut input } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: DestSink { sink , input } } HfPlusLeaf :: CycleSink { ident , location_kind , mut input , } => { transform (& mut input , seen_tees) ; HfPlusLeaf :: CycleSink { ident , location_kind , input , } } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) { match self { HfPlusLeaf :: ForEach { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> for_each (# f) ; }) ; } HfPlusLeaf :: DestSink { sink , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; graph_builders . entry (input_location_id) . or_default () . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink) ; }) ; } HfPlusLeaf :: CycleSink { ident , location_kind , input , } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; assert_eq ! (input_location_id , * location_id , "cycle_sink location mismatch") ; graph_builders . entry (* location_id) . or_default () . add_statement (parse_quote ! { # ident = # input_ident ; }) ; } } } } pub use crate :: ir :: HfPlusNode ; pub type SeenTees < 'a > = HashMap < * const RefCell < HfPlusNode < 'a > > , Rc < RefCell < HfPlusNode < 'a > > > > ; # [cfg (stageleft_macro)] impl < 'a > HfPlusNode < 'a > { pub fn compile_network < D : Deploy < 'a > + 'a > (& mut self , compile_env : & D :: CompileEnv , seen_tees : & mut SeenTees < 'a > , nodes : & HashMap < usize , D :: Process > , clusters : & HashMap < usize , D :: Cluster > ,) { self . transform_children (| n , s | n . compile_network :: < D > (compile_env , s , nodes , clusters) , seen_tees ,) ; if let HfPlusNode :: Network { from_location , to_location , instantiate_fn , .. } = self { let (sink_expr , source_expr , connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { let ((sink , source) , connect_fn) = match (from_location , to_location) { (LocationId :: Process (from) , LocationId :: Process (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: o2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Process (from) , LocationId :: Cluster (to)) => { let from_node = nodes . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_process_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: o2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: o2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Process (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = nodes . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_process_port (& to_node) ; (D :: m2o_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2o_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } (LocationId :: Cluster (from) , LocationId :: Cluster (to)) => { let from_node = clusters . get (from) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , from) }) . clone () ; let to_node = clusters . get (to) . unwrap_or_else (| | { panic ! ("A location used in the graph was not instantiated: {}" , to) }) . clone () ; let sink_port = D :: allocate_cluster_port (& from_node) ; let source_port = D :: allocate_cluster_port (& to_node) ; (D :: m2m_sink_source (compile_env , & from_node , & sink_port , & to_node , & source_port ,) , Box :: new (move | | { D :: m2m_connect (& from_node , & sink_port , & to_node , & source_port) }) as Box < dyn Fn () + 'a > ,) } } ; (sink , source , connect_fn) } DebugInstantiate :: Finalized (_ , _ , _) => panic ! ("network already finalized") , } ; * instantiate_fn = DebugInstantiate :: Finalized (sink_expr , source_expr , connect_fn) ; } } pub fn connect_network (& mut self , seen_tees : & mut SeenTees < 'a >) { self . transform_children (| n , s | n . connect_network (s) , seen_tees) ; if let HfPlusNode :: Network { instantiate_fn , .. } = self { match instantiate_fn { DebugInstantiate :: Building () => panic ! ("network not built") , DebugInstantiate :: Finalized (_ , _ , ref connect_fn) => { connect_fn () ; } } } } pub fn transform_children (& mut self , mut transform : impl FnMut (& mut HfPlusNode < 'a > , & mut SeenTees < 'a >) , seen_tees : & mut SeenTees < 'a > ,) { match self { HfPlusNode :: Placeholder => { panic ! () ; } HfPlusNode :: Source { .. } => { } HfPlusNode :: CycleSource { .. } => { } HfPlusNode :: Tee { inner } => { if let Some (transformed) = seen_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { * inner = transformed . clone () ; } else { let transformed_cell = Rc :: new (RefCell :: new (HfPlusNode :: Placeholder)) ; seen_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , transformed_cell . clone () ,) ; let mut orig = inner . replace (HfPlusNode :: Placeholder) ; transform (& mut orig , seen_tees) ; * transformed_cell . borrow_mut () = orig ; * inner = transformed_cell ; } } HfPlusNode :: Persist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Unpersist (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Delta (inner) => transform (inner . as_mut () , seen_tees) , HfPlusNode :: Union (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossProduct (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: CrossSingleton (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Join (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Difference (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: AntiJoin (left , right) => { transform (left . as_mut () , seen_tees) ; transform (right . as_mut () , seen_tees) ; } HfPlusNode :: Map { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FlatMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Filter { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FilterMap { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Sort (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: DeferTick (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Enumerate (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Inspect { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Unique (input) => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Fold { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: FoldKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Reduce { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: ReduceKeyed { input , .. } => { transform (input . as_mut () , seen_tees) ; } HfPlusNode :: Network { input , .. } => { transform (input . as_mut () , seen_tees) ; } } } pub fn emit (& self , graph_builders : & mut BTreeMap < usize , FlatGraphBuilder > , built_tees : & mut HashMap < * const RefCell < HfPlusNode < 'a > > , (syn :: Ident , usize) > , next_stmt_id : & mut usize ,) -> (syn :: Ident , usize) { match self { HfPlusNode :: Placeholder => { panic ! () } HfPlusNode :: Persist (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let persist_id = * next_stmt_id ; * next_stmt_id += 1 ; let persist_ident = syn :: Ident :: new (& format ! ("stream_{}" , persist_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # persist_ident = # inner_ident -> persist ::<'static > () ; }) ; (persist_ident , location) } HfPlusNode :: Unpersist (_) => { panic ! ("Unpersist is a marker node and should have been optimized away. This is likely a compiler bug.") } HfPlusNode :: Delta (inner) => { let (inner_ident , location) = inner . emit (graph_builders , built_tees , next_stmt_id) ; let delta_id = * next_stmt_id ; * next_stmt_id += 1 ; let delta_ident = syn :: Ident :: new (& format ! ("stream_{}" , delta_id) , Span :: call_site ()) ; let builder = graph_builders . entry (location) . or_default () ; builder . add_statement (parse_quote ! { # delta_ident = # inner_ident -> multiset_delta () ; }) ; (delta_ident , location) } HfPlusNode :: Source { source , location_kind , } => { let source_id = * next_stmt_id ; * next_stmt_id += 1 ; let source_ident = syn :: Ident :: new (& format ! ("stream_{}" , source_id) , Span :: call_site ()) ; let source_stmt = match source { HfPlusSource :: Stream (expr) => { parse_quote ! { # source_ident = source_stream (# expr) ; } } HfPlusSource :: Iter (expr) => { parse_quote ! { # source_ident = source_iter (# expr) ; } } HfPlusSource :: Interval (expr) => { parse_quote ! { # source_ident = source_interval (# expr) ; } } HfPlusSource :: Spin () => { parse_quote ! { # source_ident = spin () ; } } } ; let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; graph_builders . entry (* location_id) . or_default () . add_statement (source_stmt) ; (source_ident , * location_id) } HfPlusNode :: CycleSource { ident , location_kind , } => { let location_id = match location_kind { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; (ident . clone () , * location_id) } HfPlusNode :: Tee { inner } => { if let Some (ret) = built_tees . get (& (inner . as_ref () as * const RefCell < HfPlusNode >)) { ret . clone () } else { let (inner_ident , inner_location_id) = inner . borrow () . emit (graph_builders , built_tees , next_stmt_id) ; let tee_id = * next_stmt_id ; * next_stmt_id += 1 ; let tee_ident = syn :: Ident :: new (& format ! ("stream_{}" , tee_id) , Span :: call_site ()) ; let builder = graph_builders . entry (inner_location_id) . or_default () ; builder . add_statement (parse_quote ! { # tee_ident = # inner_ident -> tee () ; }) ; built_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode > , (tee_ident . clone () , inner_location_id) ,) ; (tee_ident , inner_location_id) } } HfPlusNode :: Union (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "union inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let union_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # union_ident = union () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [0] # union_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # union_ident ; }) ; (union_ident , left_location_id) } HfPlusNode :: CrossSingleton (left , right) => { let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "cross_singleton inputs must be in the same location") ; let union_id = * next_stmt_id ; * next_stmt_id += 1 ; let cross_ident = syn :: Ident :: new (& format ! ("stream_{}" , union_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; builder . add_statement (parse_quote ! { # cross_ident = cross_singleton () ; }) ; builder . add_statement (parse_quote ! { # left_ident -> [input] # cross_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [single] # cross_ident ; }) ; (cross_ident , left_location_id) } HfPlusNode :: CrossProduct (..) | HfPlusNode :: Join (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: CrossProduct (..)) { parse_quote ! (cross_join_multiset) } else { parse_quote ! (join_multiset) } ; let (HfPlusNode :: CrossProduct (left , right) | HfPlusNode :: Join (left , right)) = self else { unreachable ! () } ; let (left_inner , left_was_persist) = if let HfPlusNode :: Persist (left) = left . as_ref () { (left , true) } else { (left , false) } ; let (right_inner , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left_inner . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right_inner . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "join / cross product inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; match (left_was_persist , right_was_persist) { (true , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'static > () ; }) ; } (true , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'static , 'tick > () ; }) ; } (false , true) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } (false , false) => { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } } ; builder . add_statement (parse_quote ! { # left_ident -> [0] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [1] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Difference (..) | HfPlusNode :: AntiJoin (..) => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Difference (..)) { parse_quote ! (difference_multiset) } else { parse_quote ! (anti_join_multiset) } ; let (HfPlusNode :: Difference (left , right) | HfPlusNode :: AntiJoin (left , right)) = self else { unreachable ! () } ; let (right , right_was_persist) = if let HfPlusNode :: Persist (right) = right . as_ref () { (right , true) } else { (right , false) } ; let (left_ident , left_location_id) = left . emit (graph_builders , built_tees , next_stmt_id) ; let (right_ident , right_location_id) = right . emit (graph_builders , built_tees , next_stmt_id) ; assert_eq ! (left_location_id , right_location_id , "difference / anti join inputs must be in the same location") ; let stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , stream_id) , Span :: call_site ()) ; let builder = graph_builders . entry (left_location_id) . or_default () ; if right_was_persist { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'static > () ; }) ; } else { builder . add_statement (parse_quote ! { # stream_ident = # operator ::<'tick , 'tick > () ; }) ; } builder . add_statement (parse_quote ! { # left_ident -> [pos] # stream_ident ; }) ; builder . add_statement (parse_quote ! { # right_ident -> [neg] # stream_ident ; }) ; (stream_ident , left_location_id) } HfPlusNode :: Map { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let map_id = * next_stmt_id ; * next_stmt_id += 1 ; let map_ident = syn :: Ident :: new (& format ! ("stream_{}" , map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # map_ident = # input_ident -> map (# f) ; }) ; (map_ident , input_location_id) } HfPlusNode :: FlatMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let flat_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let flat_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , flat_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # flat_map_ident = # input_ident -> flat_map (# f) ; }) ; (flat_map_ident , input_location_id) } HfPlusNode :: Filter { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_ident = # input_ident -> filter (# f) ; }) ; (filter_ident , input_location_id) } HfPlusNode :: FilterMap { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let filter_map_id = * next_stmt_id ; * next_stmt_id += 1 ; let filter_map_ident = syn :: Ident :: new (& format ! ("stream_{}" , filter_map_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # filter_map_ident = # input_ident -> filter_map (# f) ; }) ; (filter_map_ident , input_location_id) } HfPlusNode :: Sort (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sort_id = * next_stmt_id ; * next_stmt_id += 1 ; let sort_ident = syn :: Ident :: new (& format ! ("stream_{}" , sort_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # sort_ident = # input_ident -> sort () ; }) ; (sort_ident , input_location_id) } HfPlusNode :: DeferTick (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let defer_tick_id = * next_stmt_id ; * next_stmt_id += 1 ; let defer_tick_ident = syn :: Ident :: new (& format ! ("stream_{}" , defer_tick_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # defer_tick_ident = # input_ident -> defer_tick_lazy () ; }) ; (defer_tick_ident , input_location_id) } HfPlusNode :: Enumerate (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let enumerate_id = * next_stmt_id ; * next_stmt_id += 1 ; let enumerate_ident = syn :: Ident :: new (& format ! ("stream_{}" , enumerate_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # enumerate_ident = # input_ident -> enumerate () ; }) ; (enumerate_ident , input_location_id) } HfPlusNode :: Inspect { f , input } => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let inspect_id = * next_stmt_id ; * next_stmt_id += 1 ; let inspect_ident = syn :: Ident :: new (& format ! ("stream_{}" , inspect_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # inspect_ident = # input_ident -> inspect (# f) ; }) ; (inspect_ident , input_location_id) } HfPlusNode :: Unique (input) => { let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let unique_id = * next_stmt_id ; * next_stmt_id += 1 ; let unique_ident = syn :: Ident :: new (& format ! ("stream_{}" , unique_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; builder . add_statement (parse_quote ! { # unique_ident = # input_ident -> unique ::<'tick > () ; }) ; (unique_ident , input_location_id) } HfPlusNode :: Fold { .. } | HfPlusNode :: FoldKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Fold { .. }) { parse_quote ! (fold) } else { parse_quote ! (fold_keyed) } ; let (HfPlusNode :: Fold { init , acc , input } | HfPlusNode :: FoldKeyed { init , acc , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let fold_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'static > (# init , # acc) ; }) ; } else { builder . add_statement (parse_quote ! { # fold_ident = # input_ident -> # operator ::<'tick > (# init , # acc) ; }) ; } (fold_ident , input_location_id) } HfPlusNode :: Reduce { .. } | HfPlusNode :: ReduceKeyed { .. } => { let operator : syn :: Ident = if matches ! (self , HfPlusNode :: Reduce { .. }) { parse_quote ! (reduce) } else { parse_quote ! (reduce_keyed) } ; let (HfPlusNode :: Reduce { f , input } | HfPlusNode :: ReduceKeyed { f , input }) = self else { unreachable ! () } ; let (input , input_was_persist) = if let HfPlusNode :: Persist (input) = input . as_ref () { (input , true) } else { (input , false) } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let reduce_id = * next_stmt_id ; * next_stmt_id += 1 ; let reduce_ident = syn :: Ident :: new (& format ! ("stream_{}" , reduce_id) , Span :: call_site ()) ; let builder = graph_builders . entry (input_location_id) . or_default () ; if input_was_persist { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'static > (# f) ; }) ; } else { builder . add_statement (parse_quote ! { # reduce_ident = # input_ident -> # operator ::<'tick > (# f) ; }) ; } (reduce_ident , input_location_id) } HfPlusNode :: Network { from_location : _ , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input , } => { let (sink_expr , source_expr , _connect_fn) = match instantiate_fn { DebugInstantiate :: Building () => { panic ! ("Expected the network to be finalized") } DebugInstantiate :: Finalized (sink , source , connect_fn) => { (sink , source , connect_fn) } } ; let (input_ident , input_location_id) = input . emit (graph_builders , built_tees , next_stmt_id) ; let sender_builder = graph_builders . entry (input_location_id) . or_default () ; if let Some (serialize_pipeline) = serialize_pipeline { sender_builder . add_statement (parse_quote ! { # input_ident -> # serialize_pipeline -> dest_sink (# sink_expr) ; }) ; } else { sender_builder . add_statement (parse_quote ! { # input_ident -> dest_sink (# sink_expr) ; }) ; } let to_id = match to_location { LocationId :: Process (id) => id , LocationId :: Cluster (id) => id , } ; let receiver_builder = graph_builders . entry (* to_id) . or_default () ; let receiver_stream_id = * next_stmt_id ; * next_stmt_id += 1 ; let receiver_stream_ident = syn :: Ident :: new (& format ! ("stream_{}" , receiver_stream_id) , Span :: call_site ()) ; if let Some (deserialize_pipeline) = deserialize_pipeline { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) -> # deserialize_pipeline ; }) ; } else { receiver_builder . add_statement (parse_quote ! { # receiver_stream_ident = source_stream (# source_expr) ; }) ; } (receiver_stream_ident , * to_id) } } } } } pub mod persist_pullup { pub use std :: cell :: RefCell ; pub use std :: collections :: HashSet ; pub use std :: ops :: Deref ; pub use crate :: ir :: * ; pub fn persist_pullup_node < 'a > (node : & mut HfPlusNode < 'a > , seen_tees : & mut SeenTees < 'a > , persist_pulled_tees : & mut HashSet < * const RefCell < HfPlusNode < 'a > > > ,) { node . transform_children (| n , s | persist_pullup_node (n , s , persist_pulled_tees) , seen_tees ,) ; match node { HfPlusNode :: Unpersist (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Unpersist (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Delta (box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Delta (box HfPlusNode :: Persist (box behind_persist)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = behind_persist ; } else { unreachable ! () } } HfPlusNode :: Tee { inner } => { if persist_pulled_tees . contains (& (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >)) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } else { let inner_borrow = inner . borrow () ; if let HfPlusNode :: Persist (_) = inner_borrow . deref () { drop (inner_borrow) ; persist_pulled_tees . insert (inner . as_ref () as * const RefCell < HfPlusNode < 'a > >) ; if let HfPlusNode :: Persist (box behind_persist) = inner . replace (HfPlusNode :: Placeholder) { * inner . borrow_mut () = behind_persist ; } else { unreachable ! () } * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Tee { inner : inner . clone () , })) ; } } } HfPlusNode :: Map { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: Map { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Map { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: FlatMap { f : _ , input : box HfPlusNode :: Persist (_) , } => { if let HfPlusNode :: FlatMap { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: FlatMap { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Filter { f : _ , input : deref!(HfPlusNode :: Persist (_)) , } => { if let HfPlusNode :: Filter { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Filter { f , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Network { input : box HfPlusNode :: Persist (_) , .. } => { if let HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Network { from_location , to_location , serialize_pipeline , instantiate_fn , deserialize_pipeline , input : behind_persist , })) ; } else { unreachable ! () } } HfPlusNode :: Union (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Union (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Union (left , right))) ; } else { unreachable ! () } } HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: CrossProduct (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right) ,) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: CrossProduct (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,) ,)))) ; } else { unreachable ! () } } HfPlusNode :: Join (box HfPlusNode :: Persist (_) , box HfPlusNode :: Persist (_)) => { if let HfPlusNode :: Join (box HfPlusNode :: Persist (left) , box HfPlusNode :: Persist (right)) = std :: mem :: replace (node , HfPlusNode :: Placeholder) { * node = HfPlusNode :: Persist (Box :: new (HfPlusNode :: Delta (Box :: new (HfPlusNode :: Join (Box :: new (HfPlusNode :: Persist (left)) , Box :: new (HfPlusNode :: Persist (right)) ,))))) ; } else { unreachable ! () } } _ => { } } } pub fn persist_pullup (ir : Vec < HfPlusLeaf >) -> Vec < HfPlusLeaf > { let mut seen_tees = Default :: default () ; let mut persist_pulled_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| n , s | persist_pullup_node (n , s , & mut persist_pulled_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn persist_pullup_through_map () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } # [test] fn persist_pullup_behind_tee () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; let before_tee = flow . source_iter (& process , q ! (0 .. 10)) . tick_batch () . persist () ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; before_tee . clone () . map (q ! (| v | v + 1)) . all_ticks () . for_each (q ! (| n | println ! ("{}" , n))) ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let optimized = built . optimize_with (super :: persist_pullup) ; insta :: assert_debug_snapshot ! (optimized . ir ()) ; for (id , graph) in optimized . compile_no_network :: < MultiGraph > () . hydroflow_ir () { insta :: with_settings ! ({ snapshot_suffix => format ! ("surface_graph_{id}") } , { insta :: assert_snapshot ! (graph . surface_syntax_string ()) ; }) ; } } } } pub mod profiler { pub use std :: cell :: RefCell ; pub use hydroflow :: futures :: channel :: mpsc :: UnboundedSender ; pub use stageleft :: * ; pub use crate as hydroflow_plus ; pub use crate :: ir :: * ; pub use crate :: RuntimeContext ; pub fn increment_counter (count : & mut u64) { * count += 1 ; } pub fn quoted_any_fn < 'a , F : Fn (& usize) + 'a , Q : IntoQuotedMut < 'a , F > > (q : Q) -> Q { q } # [doc = " Add a profiling node before each node to count the cardinality of its input"] pub fn add_profiling_node < 'a > (node : & mut HfPlusNode < 'a > , _context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > , id : & mut u32 , seen_tees : & mut SeenTees < 'a > ,) { let my_id = * id ; * id += 1 ; node . transform_children (| node , seen_tees | { add_profiling_node (node , _context , counters , counter_queue , id , seen_tees) } , seen_tees ,) ; let orig_node = std :: mem :: replace (node , HfPlusNode :: Placeholder) ; * node = HfPlusNode :: Inspect { f : quoted_any_fn (q ! ({ counter_queue . borrow () . unbounded_send ((my_id as usize , counters . borrow () [my_id as usize])) . unwrap () ; counters . borrow_mut () [my_id as usize] = 0 ; move | _ | { hydroflow_plus :: profiler :: increment_counter (& mut counters . borrow_mut () [my_id as usize] ,) ; } })) . splice () . into () , input : Box :: new (orig_node) , } } # [doc = " Count the cardinality of each input and periodically output to a file"] pub fn profiling < 'a > (ir : Vec < HfPlusLeaf < 'a > > , context : RuntimeContext < 'a > , counters : RuntimeData < & 'a RefCell < Vec < u64 > > > , counter_queue : RuntimeData < & 'a RefCell < UnboundedSender < (usize , u64) > > > ,) -> Vec < HfPlusLeaf < 'a > > { let mut id = 0 ; let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | { add_profiling_node (node , context , counters , counter_queue , & mut id , seen_tees) } , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use stageleft :: * ; use crate :: deploy :: MultiGraph ; # [test] fn profiler_wrapping_all_operators () { let flow = crate :: builder :: FlowBuilder :: new () ; let process = flow . process :: < () > () ; flow . source_iter (& process , q ! (0 .. 10)) . map (q ! (| v | v + 1)) . for_each (q ! (| n | println ! ("{}" , n))) ; let runtime_context = flow . runtime_context () ; let built = flow . finalize () ; insta :: assert_debug_snapshot ! (& built . ir ()) ; let counters = RuntimeData :: new ("Fake") ; let counter_queue = RuntimeData :: new ("Fake") ; let pushed_down = built . with_default_optimize () . optimize_with (| ir | super :: profiling (ir , runtime_context , counters , counter_queue)) ; insta :: assert_debug_snapshot ! (& pushed_down . ir ()) ; let _ = pushed_down . compile_no_network :: < MultiGraph > () ; } } } pub mod properties { pub use std :: collections :: HashSet ; pub use stageleft :: * ; pub use crate :: ir :: { HfPlusLeaf , HfPlusNode , SeenTees } ; pub use crate :: properties :: PropertyDatabase ; # [doc = " Allows us to convert the hydroflow datatype for folds to a binary operation for the algebra"] # [doc = " property tests."] # [allow (dead_code)] pub fn convert_hf_to_binary < I , A : Default , F : Fn (& mut A , I) > (f : F) -> impl Fn (I , I) -> A { move | a , b | { let mut acc = Default :: default () ; f (& mut acc , a) ; f (& mut acc , b) ; acc } } # [cfg (stageleft_macro)] impl PropertyDatabase { # [doc = " Tags the expression as commutative."] pub fn add_commutative_tag < 'a , I , A , F : Fn (& mut A , I) , Q : Quoted < 'a , F > + Clone > (& mut self , expr : Q ,) -> Q { let expr_clone = expr . clone () ; self . commutative . insert (expr_clone . splice ()) ; expr } pub fn is_tagged_commutative (& self , expr : & syn :: Expr) -> bool { self . commutative . contains (expr) } } pub fn properties_optimize_node < 'a > (node : & mut HfPlusNode < 'a > , db : & PropertyDatabase , seen_tees : & mut SeenTees < 'a > ,) { node . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , seen_tees ,) ; match node { HfPlusNode :: ReduceKeyed { f , .. } if db . is_tagged_commutative (& f . 0) => { dbg ! ("IDENTIFIED COMMUTATIVE OPTIMIZATION for {:?}" , & f) ; } _ => { } } } pub fn properties_optimize < 'a > (ir : Vec < HfPlusLeaf < 'a > > , db : & PropertyDatabase ,) -> Vec < HfPlusLeaf < 'a > > { let mut seen_tees = Default :: default () ; ir . into_iter () . map (| l | { l . transform_children (| node , seen_tees | properties_optimize_node (node , db , seen_tees) , & mut seen_tees ,) }) . collect () } # [cfg (stageleft_macro)] # [cfg (test)] mod tests { use super :: * ; use crate :: deploy :: SingleProcessGraph ; use crate :: FlowBuilder ; # [test] fn test_property_database () { let mut db = PropertyDatabase :: default () ; assert ! (! db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; let _ = db . add_commutative_tag (q ! (| a : & mut i32 , b : i32 | * a += b)) ; assert ! (db . is_tagged_commutative (& (q ! (| a : & mut i32 , b : i32 | * a += b) . splice ()))) ; } # [test] fn test_property_optimized () { let flow = FlowBuilder :: new () ; let mut database = PropertyDatabase :: default () ; let process = flow . process :: < () > () ; let counter_func = q ! (| count : & mut i32 , _ | * count += 1) ; let _ = database . add_commutative_tag (counter_func) ; flow . source_iter (& process , q ! (vec ! [])) . map (q ! (| string : String | (string , ()))) . tick_batch () . fold_keyed (q ! (|| 0) , counter_func) . all_ticks () . for_each (q ! (| (string , count) | println ! ("{}: {}" , string , count))) ; let built = flow . finalize () . optimize_with (| ir | properties_optimize (ir , & database)) . with_default_optimize () ; insta :: assert_debug_snapshot ! (built . ir ()) ; let _ = built . compile_no_network :: < SingleProcessGraph > () ; } } } pub use crate :: RuntimeContext ; # [cfg (stageleft_macro)] impl Copy for RuntimeContext < '_ > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < & 'a Context > for RuntimeContext < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (quote ! (& context))) } } pub use crate :: HfCompiled ; # [cfg (stageleft_macro)] impl < 'a , ID > HfCompiled < 'a , ID > { pub fn hydroflow_ir (& self) -> & BTreeMap < usize , HydroflowGraph > { & self . hydroflow_ir } } # [cfg (stageleft_macro)] impl < 'a > HfCompiled < 'a , usize > { pub fn with_dynamic_id (self , id : impl Quoted < 'a , usize >) -> HfBuiltWithId < 'a > { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; let mut conditioned_tokens = None ; for (subgraph_id , flat_graph) in self . hydroflow_ir { let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; let my_extra_stmts = self . extra_stmts . get (& subgraph_id) . cloned () . unwrap_or_default () ; if let Some (conditioned_tokens) = conditioned_tokens . as_mut () { * conditioned_tokens = syn :: parse_quote ! { # conditioned_tokens else if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } } ; } else { conditioned_tokens = Some (syn :: parse_quote ! { if __given_id == # subgraph_id { # (# my_extra_stmts) * # tokens } }) ; } } let conditioned_tokens : TokenStream = conditioned_tokens . unwrap () ; let id = id . splice () ; HfBuiltWithId { tokens : syn :: parse_quote ! ({ let __given_id = # id ; # conditioned_tokens else { panic ! ("Invalid node id: {}" , __given_id) ; } }) , _phantom : PhantomData , } } } # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfCompiled < 'a , () > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfCompiled < 'a , () > { fn to_tokens (mut self) -> (Option < TokenStream > , Option < TokenStream >) { let hydroflow_crate = proc_macro_crate :: crate_name ("hydroflow_plus") . expect ("hydroflow_plus should be present in `Cargo.toml`") ; let root = match hydroflow_crate { proc_macro_crate :: FoundCrate :: Itself => quote ! { hydroflow_plus } , proc_macro_crate :: FoundCrate :: Name (name) => { let ident = syn :: Ident :: new (& name , proc_macro2 :: Span :: call_site ()) ; quote ! { # ident } } } ; if self . hydroflow_ir . len () != 1 { panic ! ("Expected exactly one subgraph in the Hydroflow IR") ; } let flat_graph = self . hydroflow_ir . remove (& 0) . unwrap () ; let partitioned_graph = partition_graph (flat_graph) . expect ("Failed to partition (cycle detected).") ; let mut diagnostics = Vec :: new () ; let tokens = partitioned_graph . as_code (& root , true , quote :: quote ! () , & mut diagnostics) ; (None , Some (tokens)) } } pub use crate :: HfBuiltWithId ; # [cfg (stageleft_macro)] impl < 'a > Quoted < 'a , Hydroflow < 'a > > for HfBuiltWithId < 'a > { } # [cfg (stageleft_macro)] impl < 'a > FreeVariable < Hydroflow < 'a > > for HfBuiltWithId < 'a > { fn to_tokens (self) -> (Option < TokenStream > , Option < TokenStream >) { (None , Some (self . tokens)) } }
[INFO] [stdout]   |
[INFO] [stdout] 
[INFO] [stdout] 
[INFO] [stdout] error: `box` patterns have been removed (feature `box_patterns`)
[INFO] [stdout]  --> /opt/rustwide/target/debug/build/hydroflow_plus/5672655b657d1e44/out/lib_pub.rs:1:93826
[INFO] [stdout]   |
[INFO] [stdout] 1 | ...Persist (_) , } => { if let HfPlusNode :: Filter { f , input : box HfPlusNode :: Persist (behind_persist) , } = std :: mem :: repl...
[INFO] [stdout]   |                                                                   ^^^
[INFO] [stdout]   |
[INFO] [stdout]   = help: enable feature `deref_patterns` instead and...
[INFO] [stdout] help: ...if possible just remove keyword `box`...
[INFO] [stdout]   |
[WARN] too much data in the log, truncating it
