######################################################
# FSYS: File System IO for Rust
# Copyright (c) 2024 James Gober <
######################################################
[package]
name    = "fsys"
version = "1.0.0"

# METADATA
readme  = "README.md"
license = "Apache-2.0 OR MIT"

# RUST VERSION
edition = "2021"
rust-version = "1.75"

# LINKS
documentation = "https://docs.rs/fsys"
repository    = "https://github.com/jamesgober/fsys-rs"
homepage      = "https://github.com/jamesgober/fsys-rs"

# INCLUDES
include = [
    "src/**/*",
    "tests/**/*",
    "benches/**/*",
    "examples/**/*",
    "Cargo.toml",
    "README.md",
    "LICENSE-APACHE",
    "LICENSE-MIT",
    "CHANGELOG.md",
]
# `fuzz/` is intentionally NOT included — it's a separate cargo-fuzz
# workspace with its own `Cargo.toml` (`cargo-fuzz = true` in
# `[package.metadata]`). The fuzz crate is published separately if
# at all and should not be packaged into the main library crate.
# DESCRIPTION
# Storage-foundation framing — leads with the target audience (Rust
# storage engines), names five concrete capabilities (journal, io_uring,
# NVMe passthrough, atomic writes, cross-platform durability). 127 chars,
# under the 140-char crates.io card limit. No filler adjectives.
description = "Filesystem IO for Rust storage engines: journal substrate, io_uring, NVMe passthrough, atomic writes, cross-platform durability."

# KEYWORDS (max 5 per crates.io)
# Tuned for storage-engine search intent. "journal" replaces the
# prior "io" (too broad to be useful for discovery; "io" is the most
# common keyword on crates.io and produces 1000+ results). "journal"
# is our headline differentiator and matches WAL-related search.
keywords = [
    "journal",
    "filesystem",
    "storage",
    "durability",
    "nvme",
]

# CATEGORIES (max 5)
# Primary: filesystem (the obvious one). Hardware-support: NVMe
# passthrough, io_uring, PLP detection. OS: cross-platform abstraction
# over Linux / macOS / Windows. Concurrency: lock-free journal appends,
# group-commit coordinator, multi-shard batch dispatcher — adding it
# surfaces fsys in concurrency-tagged searches by storage-engine
# authors looking for foundation libraries.
categories = [
    "filesystem",
    "hardware-support",
    "os",
    "concurrency",
]

# AUTHORS
authors = [
    "James Gober <me@jamesgober.com>"
]

# DOCS.RS BUILD CONFIG
# 0.9.6 — explicit metadata. docs.rs builds with --all-features
# so users see the full surface (async + tracing). The `docsrs`
# cfg is a convention for items to render only on docs.rs (used
# by `#[cfg_attr(docsrs, doc(cfg(...)))]` annotations).
[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]


###########################
# LIBRARY
###########################
[lib]
name = "fsys"
path = "src/lib.rs"


###########################
# FEATURES
###########################
[features]
default = []
# Async layer (locked decision D-1 in `.dev/DECISIONS-0.6.0.md`).
# Adds `_async` siblings to every sync method via
# `tokio::task::spawn_blocking`; async batch ops via
# `tokio::sync::oneshot`. Pulls in tokio's `rt`, `rt-multi-thread`,
# `sync`, `macros` features.
async = ["dep:tokio"]
# Stress / soak test harnesses (locked decision D-7). Tests gated
# behind this flag run for the full 1-hour duration; without the
# flag they compile but skip the long-running body. CI nightly
# enables this for full-duration validation; dev iteration uses
# short validation runs.
stress = []
# Fuzz harness wiring. Compile-only flag — actual fuzz target binaries
# live in the `fuzz/` directory and use `cargo-fuzz`. This flag
# exists so library code that supports fuzz instrumentation can be
# conditionally enabled without it bloating release builds.
fuzz = []
# Opt-in `tracing` instrumentation. Adds spans + events on the
# write / read / journal hot paths. Off by default — the `tracing`
# macros compile to no-ops when the dep is absent, so there's
# zero overhead for non-tracing builds. Enable this in production
# observability environments where `tracing` subscribers
# (tokio-console, OpenTelemetry, etc.) are already wired.
tracing = ["dep:tracing"]
# 0.9.7 H-9 / H-7 — internal test-hooks feature. Replaces the
# system global allocator with an OOM-injecting one that tests
# can program (via thread-local size threshold) to fail allocs
# above a target size. NEVER enable in production builds —
# every allocation goes through an extra dispatch + threshold
# check. The feature is here to make the integration test
# `tests/oom_injection.rs` compileable; CI runs it as a separate
# matrix entry with `--features oom_inject` and the production
# matrix never sees it.
oom_inject = []


###########################
# DEPENDENCIES
###########################
[dependencies]
# Tokio runtime — gated behind the `async` feature flag.
# Feature set rationale (locked decision D-10 in
# `.dev/DECISIONS-0.6.0.md`):
# - `rt` + `rt-multi-thread`: required for `spawn_blocking` and
#   `#[tokio::test(flavor = "multi_thread")]` for batch tests.
# - `sync`: required for `tokio::sync::oneshot` (async batch
#   response channel per locked decision D-5).
# - `macros`: required for `#[tokio::test]`.
# `fs` was dropped in 0.6.0 — fsys's async layer uses
# `spawn_blocking` against the sync core, never tokio's fs
# primitives.
tokio = { version = "1", features = ["rt", "rt-multi-thread", "sync", "macros", "net", "time"], optional = true }

# Optional structured-event instrumentation. Gated behind the
# `tracing` feature flag; when off, the dep isn't pulled in.
# `tracing`'s macros (`trace_span!`, `debug!`, etc.) compile to
# no-ops in the absence of the dep — fsys's own code uses them
# unconditionally inside `#[cfg(feature = "tracing")]` blocks so
# the no-op-on-absent-feature property is enforced by the type
# system, not just convention.
tracing = { version = "0.1", default-features = false, optional = true }

# Bounded MPMC + oneshot channels with `select!` support.
# Used by the 0.4.0 pipeline subsystem: the group-lane work queue
# (bounded MPMC with blocking-submit backpressure), the per-batch response
# channels (oneshot), and the dispatcher's shutdown signaling channel.
# `std::sync::mpsc` is insufficient because it does not provide bounded
# MPMC nor a usable `select` primitive. `crossbeam-channel` is the
# established, near-universal choice in production Rust concurrent code,
# is API-stable across the 0.5.x series, and carries no transitive deps.
crossbeam-channel = "0.5"

# Bounded lock-free `ArrayQueue` for the 0.5.0 per-handle aligned
# buffer pool. Selected over the `crossbeam` umbrella crate (D-5 in
# `.dev/DECISIONS-0.5.0.md`): same maintainers and security posture as
# `crossbeam-channel`, ~2K LOC vs the umbrella's 10–20× larger surface,
# version-pinnable independently. No transitive deps.
crossbeam-queue = "0.3"

# `CachePadded<T>` newtype that aligns and pads its inner value to
# the platform's cache-line size. Used in 0.9.1 to eliminate the
# false-sharing ping-pong between the journal's `next_lsn` (mutated
# by every appender) and `synced_lsn` (read by every group-commit
# follower). Same maintainers as crossbeam-channel / crossbeam-queue;
# zero transitive deps; const-friendly construction.
crossbeam-utils = { version = "0.8", default-features = false }

# Hardware-accelerated CRC-32C (Castagnoli, RFC 3720). Runtime
# CPUID dispatch on x86_64 (SSE4.2 `crc32` instruction) and ARMv8
# (CRC extensions); pure-Rust fallback elsewhere. ~30 GB/s on
# modern x86 vs the previous ~2 GB/s software lookup table — the
# 5×+ speedup on the journal's per-frame CRC is the load-bearing
# 0.9.1 fix for the bulk-load regression vs v0.8.5.
# Selected over `crc32fast` (which targets the *standard*
# CRC-32 polynomial, not Castagnoli) and over hand-rolled
# `target_feature` SIMD (would require nightly + MSRV bump).
# `crc32c` 0.6 is MSRV 1.46-clean and dependency-free.
crc32c = "0.6"

# `Mutex` + `Condvar` with futex-backed wait/wake (Linux), no
# poisoning, and `wait_for` / `wait_while` ergonomics that the
# std-lib equivalents lack. Used in 0.9.1 to replace the journal's
# blocking `Mutex<()>` group-commit gate with a leader/follower
# Condvar pattern that ports v0.8.5 emdb's working scheme.
# Smaller, faster, and less footgun-prone than `std::sync::{Mutex,
# Condvar}` for the deep-internal coordination paths fsys uses.
parking_lot = "0.12"

# Cross-platform memory-mapped IO for `Method::Mmap` (D-6 +
# `CHANGELOG.md`). The original `memmap` crate is unmaintained;
# `memmap2` is the maintained successor, widely vetted in production
# Rust storage projects (RocksDB-rs bindings, sled, etc.). Minimal
# transitive deps.
memmap2 = "0.9"

# Glob-pattern matching for `Handle::find`. Standard syntax (`*`,
# `**`, `?`, `[abc]`, `{foo,bar}`) — the de-facto pattern crate in
# the Rust ecosystem (~300k weekly downloads). Selected over
# implementing glob from scratch (which would either be incomplete
# or several hundred LOC) per locked decision D-4 in
# `.dev/DECISIONS-0.6.0.md`. Mature, well-maintained, no transitive
# bloat.
glob = "0.3"

# Syscall wrappers for Unix platforms (Linux, macOS).
# Required for O_DIRECT, pread/pwrite, fdatasync, F_FULLFSYNC, F_NOCACHE,
# and platform-specific atomic rename primitives.
[target.'cfg(unix)'.dependencies]
libc = { version = "0.2", default-features = false }

# Linux-only: io_uring submission/completion ring for the elite
# `Method::Direct` path (locked decision #1 in
# `.dev/DECISIONS-0.5.0.md`). Hard dep on Linux — no Cargo feature
# flag — with graceful runtime fallback to `O_DIRECT` + `pwrite` +
# `fdatasync` when `io_uring_setup` fails. Selected over the multiple
# alternative crates (`io_uring` underscored, `linux-io-uring`, `rio`,
# `tokio-uring`, `glommio`) per D-1: `io-uring` (tokio-rs) is the
# canonical low-level binding with no async-runtime opinions, used by
# quinn, monoio, glommio internally and the Linux kernel test
# infrastructure. Pure Rust over `libc`, ~zero transitive deps.
[target.'cfg(target_os = "linux")'.dependencies]
# Pinned to 0.6.x. The 0.7.x line triggers a known rustc 1.95 ICE
# (`check_mod_deathness` panic) when the `IoUring` type is wrapped
# in `std::sync::Mutex` or `RwLock`. 0.6.x is the latest line not
# affected by this interaction. Re-evaluate when 0.7.y bumps to a
# fixed rustc.
io-uring = "0.6"

# Win32 API bindings for Windows IO primitives:
# CreateFileW (FILE_FLAG_NO_BUFFERING / WRITE_THROUGH), FlushFileBuffers,
# MoveFileExW, GetDiskFreeSpaceW, ReadFile/WriteFile, SetFilePointerEx.
# 0.5.0 additionally uses:
# - IOCTL_STORAGE_QUERY_PROPERTY (StorageDeviceWriteCacheProperty,
#   StorageAccessAlignmentProperty) for hardware probe.
# - CreateNamedPipeW for the crash-test harness's deterministic
#   sync-primitive kill points (D-2).
[target.'cfg(windows)'.dependencies]
windows-sys = { version = "0.59", features = [
    "Win32_Storage_FileSystem",
    "Win32_Storage_IscsiDisc",
    "Win32_Foundation",
    "Win32_System_IO",
    "Win32_System_Ioctl",
    "Win32_System_Pipes",
    "Win32_System_SystemInformation",
    "Win32_Security",
    # 0.6.0: Windows ACL preservation in `Handle::write_copy` (D-8 in
    # `.dev/DECISIONS-0.6.0.md`) uses `GetNamedSecurityInfoW` /
    # `SetNamedSecurityInfoW` from this module.
    "Win32_Security_Authorization",
] }


###########################
# DEV DEPENDENCIES
###########################
[dev-dependencies]
# Criterion is the standard micro-benchmarking framework for Rust.
# Used for write/read/method-comparison benchmarks required by the 0.3.0 spec.
criterion = { version = "0.5", features = ["html_reports"] }


###########################
# BENCHMARKS
###########################
[[bench]]
name    = "single_write"
harness = false

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

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

# 0.4.0 group-lane benchmarks.
# Floor-target validation runs on the Linux primary box; Windows
# numbers are the Windows-specific baseline for regression detection
# (decision D-3 in `.dev/DECISIONS-0.4.0.md`).
[[bench]]
name    = "batch_throughput"
harness = false

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

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

# 0.5.0 method-matrix and per-method workload benchmarks. The
# `method_payload_matrix` is the canonical regression surface
# (4 methods × 4 payloads × 4 ops). `mmap_workloads` validates the
# Mmap suitability fallback (R-2'') and the page-aligned fast path.
# `direct_iouring` is the post-stub baseline for `Method::Direct` —
# re-run after the io_uring path is unstubbed in 0.5.x to measure
# the io_uring uplift.
[[bench]]
name    = "method_payload_matrix"
harness = false

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

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

# 0.7.0 G — performance regression infrastructure.
# Native vs spawn_blocking comparison validates the load-bearing
# 2× advantage from D-8. Tail validation harness validates the
# p99.9 within 10× p50 target from D-5.
[[bench]]
name              = "async_native_vs_blocking"
harness           = false
required-features = ["async"]

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

# 0.8.0 F — canonical performance matrix vs std::fs / tokio peers.
# Custom main (no Criterion); produces a markdown table on stdout
# ready for `docs/BENCH.md`.
[[bench]]
name              = "matrix_with_peers"
harness           = false
required-features = ["async"]

# 0.8.0 R-1 — Journal substrate throughput vs atomic-replace.
# Measures the speedup the WAL/append + group-commit primitive
# delivers over the per-write atomic-replace primitive.
[[bench]]
name    = "journal_vs_atomic_replace"
harness = false


###########################
# EXAMPLES
###########################
# Examples 01–10, 13–16 build with the default feature set; only the
# async ones (11, 12) require the `async` feature. Cargo auto-discovers
# every `examples/*.rs` so we list only the entries that need
# `required-features`.

[[example]]
name              = "11_async_basics"
required-features = ["async"]

[[example]]
name              = "12_async_batch"
required-features = ["async"]


###########################
# PROFILE RELEASE
###########################
[profile.release]
opt-level = 3
lto = "thin"
codegen-units = 1
strip = "symbols"

###########################
# PROFILE BENCH
###########################
[profile.bench]
opt-level = 3
lto = "thin"
codegen-units = 1
debug = true
