[package]
name = "lazily"
version = "0.25.0"
edition = "2024"
# let_chains is used throughout (context.rs, async_context.rs, state_machine.rs);
# it stabilized in Rust 1.88. Declare MSRV so cargo's resolver surfaces it.
rust-version = "1.88"
description = "Lazy reactive signals with dependency tracking and cache invalidation"
license = "MIT"
repository = "https://github.com/lazily-hub/lazily-rs"
keywords = ["reactive", "signals", "lazy", "dependency-tracking", "cache"]
categories = ["data-structures"]
# The signaling/ subtree is a standalone TypeScript Cloudflare Worker + client,
# not part of the Rust crate; keep it out of the published package.
exclude = ["signaling/"]

[workspace]
members = ["macros"]
resolver = "3"

[lib]
crate-type = ["lib", "cdylib"]

[features]
# Thread-safe reactive context (lock-backed, Send + Sync). Required of any
# binding whose platform exposes preemptive threading (lazily-spec §
# "Concurrency layers are required"). Opt-in so single-threaded users don't
# pay for parking_lot; the `std_sync_mutex` toggle further swaps in
# std::sync::Mutex for a fully std-only build.
thread-safe = ["dep:parking_lot"]
# Async reactive context (future-returning, Empty/Computing/Resolved/Error slot
# lifecycle). Required of any binding whose platform exposes a suspendable
# runtime (lazily-spec § "Concurrency layers are required"). Pulls tokio +
# parking_lot (async_context uses parking_lot::Mutex internally).
async = ["dep:tokio", "dep:parking_lot"]
default = ["smallvec"]
distributed = []
# #lzlosstree: lossless full-document tree CRDT (M1 syntax-agnostic core). Builds
# on the flat text CRDT and the distributed clock primitives, so it implies
# `distributed`. Off by default until the protocol stabilizes across bindings.
lossless-tree = ["distributed"]
ffi = ["ipc", "dep:serde_json"]
instrumentation = []
ipc = ["serde"]
ipc-binary = ["ipc", "dep:postcard"]
ipc-msgpack = ["ipc", "dep:rmp-serde"]
# Loom model tests for the thread-safe context. Implies `thread-safe` so the
# model has something to test.
loom = ["thread-safe"]
serde = ["dep:serde", "smallvec?/serde"]
# #lzzcpy: POSIX shared-memory backend (`ShmBackend`) for the cross-process
# zero-copy transport — a `shm_open` + `mmap` region with an atomic bump
# allocator. Unix-only; implies `ipc` (descriptors are `ShmBlobRef`s). Off by
# default so platforms without POSIX shm (WASM, browsers) don't pull in `libc`.
shm = ["ipc", "dep:libc"]
# DEPRECATED no-op: the typed Harel state-chart engine (`ChartBuilder`,
# `StateChart`, reactive transition engine) is now part of core — pure Rust, no
# extra dependencies, always available, alongside the other core reactive
# constructs (`CellTree`, `CellMap`, `reconcile`). This alias is retained so
# existing `features = ["statechart"]` consumers keep building; it will be removed
# in a future release.
statechart = []
# `ChartDef::from_json` — load charts from a `serde_json::Value` (conformance,
# tooling, cross-language fixtures). This is the only chart surface that needs a
# dependency (serde_json), so it stays gated; the typed builder needs nothing.
statechart-json = ["dep:serde_json"]
# Switch ThreadSafeContext's inner state mutex from parking_lot::Mutex to
# std::sync::Mutex — a fully std-only thread-safe build. No-op without
# `thread-safe`. ReadStrategy::Cached still uses parking_lot::RwLock.
std_sync_mutex = ["thread-safe"]
# #jpf1: WebRTC DataChannel IPC transport — abstraction layer (sync IpcSink/Source
# bridge + permission filtering + in-memory loopback). Dependency-light.
webrtc = ["ipc", "dep:serde_json", "dep:parking_lot"]
# #webrtcbackend: concrete sans-IO str0m DataChannel backend over the `webrtc`
# abstraction. Additive + opt-in so the str0m dep tree stays out of default builds.
webrtc-str0m = ["webrtc", "dep:str0m"]
# #akp3: concrete WebSocket DataChannel backend over the `webrtc` abstraction.
# WebSocket is ordered+reliable so it satisfies DataChannel directly via an
# async-to-sync tokio bridge — no signaling/ICE. Additive + opt-in.
websocket = ["webrtc", "dep:tokio", "dep:tokio-tungstenite", "dep:futures-util"]
# Async client for the #yxjw Cloudflare signaling endpoint, so a Rust project
# (e.g. agent-doc) can depend on lazily-rs for distributed peer discovery (#s0fc).
signaling-client = ["distributed", "serde", "dep:serde_json", "dep:tokio", "dep:tokio-tungstenite", "dep:futures-util"]
tokio = ["dep:tokio"]
vec_edges = []
# #lzscalebench: gates the heavy >=1M-node scale benchmark so the default
# `cargo bench` (and `make benchmark-check`) stays fast and BENCHMARKS.md's
# generated section is unaffected. Run explicitly:
#   cargo bench --features scale-bench --bench scale
scale-bench = []
# #lzscalecompare: cross-library head-to-head against leptos_reactive (another
# lazy pull-based memo system) on the identical spreadsheet graph shape. Gated so
# the comparison dependency (`leptos_reactive`) is only pulled in for the explicit
# benchmark run, never for normal builds / `make check`:
#   cargo bench --features scale-compare --bench scale_compare
scale-compare = ["dep:leptos_reactive"]

[dependencies]
lazily-macros = { version = "=0.22.0", path = "macros" }
leptos_reactive = { version = "0.6", optional = true }
arc-swap = "1"
futures-util = { version = "0.3", optional = true, default-features = false, features = ["sink", "std"] }
libc = { version = "0.2", optional = true }
parking_lot = { version = "0.12", optional = true }
postcard = { version = "1", optional = true, features = ["alloc"] }
rmp-serde = { version = "1", optional = true }
serde = { version = "1", optional = true, features = ["derive"] }
serde_json = { version = "1", optional = true }
smallvec = { version = "1", optional = true }
str0m = { version = "0.20", optional = true }
tokio = { version = "1", optional = true, default-features = false, features = ["macros", "rt-multi-thread", "sync", "time", "net", "io-util"] }
tokio-tungstenite = { version = "0.24", optional = true, features = ["rustls-tls-webpki-roots"] }

[dev-dependencies]
criterion = "0.8"
jsonschema = { version = "0.46.8", default-features = false }
libc = "0.2"
loom = "0.7"
proptest = "1"
rmp-serde = "1"
serde_json = "1"

[[example]]
name = "tokio_sync"
required-features = ["tokio"]

[[example]]
name = "instrumentation_profile"
required-features = ["instrumentation", "thread-safe"]

# #lzwebrtcrunbook: operator driver for the live two-host WebRTC e2e run (#h6qb).
# See tasks/software/runbook-lazily-webrtc-live-e2e.md.
[[example]]
name = "webrtc_live_e2e"
required-features = ["signaling-client", "webrtc-str0m"]

[[bench]]
name = "context"
harness = false

# #lzscalebench: >=1M-node scale benchmark. Gated behind `scale-bench` so it is
# skipped by the default `cargo bench` / `make benchmark-check` and only runs on
# `cargo bench --features scale-bench --bench scale`.
[[bench]]
name = "scale"
harness = false
required-features = ["scale-bench"]

# #lzscalecompare: head-to-head vs leptos_reactive on the same graph shape.
# `cargo bench --features scale-compare --bench scale_compare`
[[bench]]
name = "scale_compare"
harness = false
required-features = ["scale-compare"]

[[bench]]
name = "profile"
harness = false
required-features = ["instrumentation"]

[[bench]]
name = "async_context"
harness = false
required-features = ["async"]

[[bench]]
name = "webrtc_transport"
harness = false
required-features = ["webrtc"]

[[bench]]
name = "tokio_sync"
harness = false
required-features = ["tokio"]
