z39/
prefs.rs

1//! Global Implementation Preferences
2use std::sync::OnceLock;
3
4// Copied from YAZ
5static DEFAULT_PREFERRED_MESSAGE_SIZE: u32 = 67108864;
6static DEFAULT_EXCEPTIONAL_RECORD_SIZE: u32 = 67108864;
7
8// Once applied, settings are globally accessible, but cannot change.
9static IMPLEMENTATION_PREFS: OnceLock<ImplementationPrefs> = OnceLock::new();
10
11/// Initialization options
12///
13/// Note the values set to true here are necessarily impacted by what
14/// message types this crate supports.
15///
16/// # References
17///
18/// * <https://www.loc.gov/z3950/agency/asn1.html#Options>
19#[derive(Debug, Default)]
20pub struct InitOptions {
21    pub search: bool,
22    pub presen: bool,
23    pub del_set: bool,
24    pub resource_report: bool,
25    pub trigger_resource_ctrl: bool,
26    pub resource_ctrl: bool,
27    pub access_ctrl: bool,
28    pub scan: bool,
29    pub sort: bool,
30    pub extended_services: bool,
31    pub level1_segmentation: bool,
32    pub level2_segmentation: bool,
33    pub concurrent_operations: bool,
34    pub named_result_sets: bool,
35}
36
37impl InitOptions {
38    /// Returns the option values sorted/positioned for building a BitString.
39    pub fn as_positioned_values(&self) -> [bool; 15] {
40        [
41            self.search,
42            self.presen,
43            self.del_set,
44            self.resource_report,
45            self.trigger_resource_ctrl,
46            self.resource_ctrl,
47            self.access_ctrl,
48            self.scan,
49            self.sort,
50            false, // Slot 9 is reserved
51            self.extended_services,
52            self.level1_segmentation,
53            self.level2_segmentation,
54            self.concurrent_operations,
55            self.named_result_sets,
56        ]
57    }
58}
59
60/// Implementation preferences specific to each client/server implemenation.
61#[derive(Debug)]
62pub struct ImplementationPrefs {
63    pub implementation_id: Option<String>,
64    pub implementation_name: Option<String>,
65    pub implementation_version: Option<String>,
66    pub preferred_message_size: u32,
67    pub exceptional_record_size: u32,
68    pub init_options: InitOptions,
69}
70
71impl Default for ImplementationPrefs {
72    fn default() -> Self {
73        ImplementationPrefs {
74            implementation_id: None,
75            implementation_name: None,
76            implementation_version: None,
77            preferred_message_size: DEFAULT_PREFERRED_MESSAGE_SIZE,
78            exceptional_record_size: DEFAULT_EXCEPTIONAL_RECORD_SIZE,
79            init_options: InitOptions::default(),
80        }
81    }
82}
83
84impl ImplementationPrefs {
85    /// Returns a reference to the globally applied ImplementationPrefs value.
86    pub fn global() -> &'static ImplementationPrefs {
87        if IMPLEMENTATION_PREFS.get().is_none() {
88            IMPLEMENTATION_PREFS
89                .set(ImplementationPrefs::default())
90                .unwrap();
91        }
92
93        IMPLEMENTATION_PREFS.get().unwrap()
94    }
95
96    /// Take ownership of a ImplementationPrefs instance and store it globally.
97    ///
98    /// May only be called once globally.
99    ///
100    /// # Panics
101    ///
102    /// Panics if called more than once.
103    pub fn apply(self) {
104        if IMPLEMENTATION_PREFS.set(self).is_err() {
105            panic!("Global ImplementationPrefs already applied");
106        }
107    }
108}