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
81
82
83
84
85
86
87
88
89
90
91
//! `SharedClassifier`: one slot owning one loaded [`IntentClassifier`].
//!
//! Each pool slot wraps a single [`SharedClassifier`]. The
//! `Arc<parking_lot::Mutex<...>>` layer is necessary because
//! [`ort::session::Session::run`](ort::session::Session) requires
//! `&mut self` while the daemon serves shared-reference dispatch.
//! Cloning the inner [`Arc`] is cheap; a clone re-circulates the
//! **same** loaded session, **NOT** a fan-out across slots. Distinct
//! slots = distinct [`SharedClassifier`] instances created via separate
//! [`IntentClassifier::load`] calls (see NL07 `ClassifierPool`).
//!
//! [`parking_lot::Mutex`] is used per the workspace memory & concurrency
//! rule (NOT [`std::sync::Mutex`]). `parking_lot` mutexes are not
//! poisoned, so a panic during `Session::run` leaves the mutex usable —
//! important for the NL07 scopeguard panic-safety contract.
//!
//! The guarded type is `!Sync` (it owns an [`ort::session::Session`]),
//! but the wrapper itself is `Send + Sync + Clone` because the
//! [`parking_lot::Mutex`] guarantees exclusive access at runtime. A
//! compile-time assertion below pins these auto-trait bounds so future
//! refactors cannot silently break them.
use crateIntentClassifier;
use Mutex;
use Arc;
/// Shared, lockable handle to a single loaded [`IntentClassifier`].
///
/// One handle = one loaded model session. Cloning is `O(1)` and
/// recirculates the same underlying session; it does NOT duplicate
/// model weights or fan out to a parallel session. To serve N
/// concurrent inferences, allocate N independent
/// [`SharedClassifier`] instances (one [`IntentClassifier::load`]
/// each) — see NL07's `ClassifierPool`.
);