global-lib 1.0.0

Process-wide values for Rust: set, define, read, edit, and remove globals by name or through typed statics, with lock-free reads. Zero dependencies.
docs.rs failed to build global-lib-1.0.0
Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.

Features

Globals by Name

  • Any type — anything Send + Sync + 'static: numbers, strings, collections, Arc<dyn Trait + Send + Sync>
  • set, define, remove, contains — set replaces a value of any type; define is set-once
  • get, try_get, value, with — a shared handle, the same with the reason for a miss, a clone, or a closure over the value in place
  • edit — changes a value through a copy; concurrent edits never lose an update
  • Your own stores — Globals::new() for an isolated set of values, or a fresh one per test, with names, len, type_of, and clear on top

Typed Statics

  • static X: Global<T> = Global::new(); — type checked at compile time, no name to hash
  • set, define, take — set returns the previous value; define gives your value back if one is already set
  • get, value, with, is_set — with is the fastest read in the crate, about 5 ns
  • edit — returns false without calling the closure when nothing is set

Reads and Writes

  • Lock-free, allocation-free reads — a hazard-pointer announcement, a borrow, a release
  • Readers share nothing they write — aggregate read throughput grows with the number of threads
  • Copy-on-write writes — serialized, never waiting for readers, and no lock is held while your closures run, so writing from inside a read or an edit cannot deadlock
  • Handles stay valid — an Arc from get keeps its value alive after it is replaced or removed

Secrets

  • Never printed — Debug lists names and types; errors name the global and the types involved, never the value
  • Bounded error text — names echoed in errors are cut to 64 characters

Installation

[dependencies]
global-lib = "1.0"

Quick Start

use global_lib::Global;

// By name: any Send + Sync + 'static type, in one process-wide store.
global_lib::set("port", 7000u16);
global_lib::define("app_name", "HiveDB")?;           // set-once

let port: u16 = global_lib::value("port").unwrap_or(8080);
global_lib::edit::<u16>("port", |p| *p += 1)?;
let len = global_lib::with::<&str, _>("app_name", |name| name.len());

// Typed: checked at compile time, no name lookup.
static MAX_CONNECTIONS: Global<usize> = Global::new();

MAX_CONNECTIONS.set(64);
let max = MAX_CONNECTIONS.with(|n| *n).unwrap_or(16);
# Ok::<(), global_lib::Error>(())

Wrong Types and Missing Values

use global_lib::Error;

global_lib::set("workers", 8u16);

// The quiet readers return None for a wrong type or a missing name.
assert_eq!(global_lib::value::<u32>("workers"), None);

// try_get and edit say why.
let err = global_lib::try_get::<u32>("workers").unwrap_err();
assert_eq!(err.to_string(), r#"global "workers" holds a u16, not a u32"#);
assert!(matches!(global_lib::try_get::<u16>("threads"), Err(Error::Missing { .. })));

A Store of Your Own

use std::sync::LazyLock;
use global_lib::Globals;

static PLUGINS: LazyLock<Globals> = LazyLock::new(Globals::new);

PLUGINS.set("compression", String::from("zstd"));
PLUGINS.set("checksum", String::from("crc32c"));
assert_eq!(PLUGINS.names(), ["checksum", "compression"]);

The free functions use one process-wide Globals, returned by global_lib::globals(). A Globals of your own keeps a group of values apart from it, and a Globals::new() per test keeps tests from seeing each other's values.

Documentation

Contributing

Contributions are welcome under the project's dual license. Before opening a pull request, please make sure:

  1. cargo fmt --all -- --check passes.
  2. cargo clippy --all-targets --all-features -- -D warnings is clean.
  3. cargo test --all-features passes.
  4. New public items include documentation and at least one example.
  5. The API reference and CHANGELOG are updated alongside code changes.