1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
//! Non-fatal diagnostics: conditions a caller must be able to see but
//! that are not failures of the operation that produced them.
//!
//! There is exactly one today — the post-commit durability shortfall in
//! [`io`](crate::io) (#365): the rename that publishes a saved index has
//! already succeeded, so the save is not an error, but the caller is
//! entitled to know that the rename may not survive power loss.
//!
//! A library must not decide unilaterally that stderr is the right place
//! for that. A service that captures its logs structurally never sees a
//! bare `eprintln!`, and a caller who does not want the line has no way
//! to turn it off. So the sink is a process-global hook the embedder
//! installs — the shape `std::panic::set_hook` uses for the same problem
//! — with a stderr default so that doing nothing still shows the
//! warning rather than dropping it.
//!
//! Why not the `log`/`tracing` facade: turbovec has no logging
//! dependency today, and a facade with no logger installed *discards*
//! the record silently, which is the one outcome #365 rules out. A hook
//! forwards into whichever facade the embedder actually uses in three
//! lines, and costs downstreams nothing.
//!
//! The slot is a single [`AtomicPtr`], not a `Mutex`/`OnceLock`: reading
//! it is one atomic load that can never block, so a warning emitted in
//! a process that has forked behaves the same as in one that has not
//! (see [`codebook`](crate::codebook) for the same requirement stated at
//! length). It is also replaceable, which set-once cells are not.
use ;
/// Sink for a non-fatal diagnostic. Receives the message body with no
/// trailing newline and no `turbovec:` prefix.
///
/// It may be called from any thread, including a rayon worker inside a
/// save, and it must not panic or unwind into the caller.
pub type WarningHook = fn;
/// Null means "no hook installed"; any other value is a `WarningHook`
/// that was cast to a data pointer by [`set_warning_hook`].
static HOOK: = new;
/// Route non-fatal diagnostics to `hook`, replacing any previous one;
/// `None` restores the stderr default.
///
/// Install it once during startup, before other threads exist: a hook
/// swapped concurrently with an in-flight warning may still see the old
/// one deliver that message. Passing a hook that suppresses everything
/// (`|_| {}`) is the supported way to silence the library.
///
/// ```
/// fn to_my_log(message: &str) {
/// eprintln!("[turbovec] {message}");
/// }
/// turbovec::set_warning_hook(Some(to_my_log));
/// turbovec::set_warning_hook(None); // back to the default
/// ```
/// Deliver `message` to the installed hook, or to stderr if there is
/// none.
pub