libmqm_constants/
lookup.rs1use libmqm_sys::MQLONG;
2
3use crate::mapping;
4
5pub trait MqConstant {
6 type Value;
7 fn mq_value(&self) -> Self::Value;
8}
9
10pub type ConstantItem<'a> = (MQLONG, &'a str);
11
12pub trait ConstLookup {
14 fn by_value(&self, value: MQLONG) -> impl Iterator<Item = &str>;
17 fn by_name(&self, name: &str) -> Option<MQLONG>;
19 fn all(&self) -> impl Iterator<Item = ConstantItem<'_>>;
21}
22
23pub struct ConstSource<P, S>(pub(crate) P, pub(crate) S);
25pub type PhfSource<'a> = ConstSource<&'a ::phf::Map<MQLONG, &'a str>, &'a [ConstantItem<'a>]>;
26pub type LinearSource<'a> = ConstSource<&'a [ConstantItem<'a>], &'a [ConstantItem<'a>]>;
27pub type BinarySearchSource<'a> = ConstSource<BinarySearch<'a>, &'a [ConstantItem<'a>]>;
28
29pub struct BinarySearch<'a>(pub(crate) &'a [ConstantItem<'a>]);
31
32pub trait HasConstLookup {
34 fn const_lookup<'a>() -> &'a (impl ConstLookup + 'static);
36}
37
38impl<P: ConstLookup, S: ConstLookup> ConstLookup for ConstSource<P, S> {
39 fn by_value(&self, value: MQLONG) -> impl Iterator<Item = &str> {
40 let Self(source, extra) = self;
41 source.by_value(value).chain(extra.by_value(value))
42 }
43
44 fn by_name(&self, name: &str) -> Option<MQLONG> {
45 let Self(source, extra) = self;
46 source.by_name(name).or_else(|| extra.by_name(name))
47 }
48
49 fn all(&self) -> impl Iterator<Item = ConstantItem<'_>> {
50 let Self(source, extra) = self;
51 source.all().chain(extra.all())
52 }
53}
54
55impl ConstLookup for BinarySearch<'_> {
56 fn by_value(&self, value: MQLONG) -> impl Iterator<Item = &str> {
57 let Self(list) = self;
58 list.binary_search_by_key(&value, |(value, ..)| *value)
59 .map(|index| list[index].1)
60 .into_iter()
61 }
62
63 fn by_name(&self, name: &str) -> Option<MQLONG> {
64 let &Self(list) = self;
65 list.by_name(name)
66 }
67
68 fn all(&self) -> impl Iterator<Item = ConstantItem<'_>> {
69 let list = &self.0;
70 list.iter().copied()
71 }
72}
73
74impl ConstLookup for &::phf::Map<MQLONG, &str> {
76 fn by_value(&self, value: MQLONG) -> impl Iterator<Item = &str> {
77 self.get(&value).copied().into_iter()
78 }
79
80 fn by_name(&self, name: &str) -> Option<MQLONG> {
81 let value: Option<&MQLONG> = mapping::MQI_BY_STRING.get(name);
82 value.filter(|v| self.get(v) == Some(&name)).copied()
83 }
84
85 fn all(&self) -> impl Iterator<Item = ConstantItem<'_>> {
86 self.entries().map(|(&v, &n)| (v, n))
87 }
88}
89
90impl ConstLookup for &[ConstantItem<'_>] {
92 fn by_value(&self, value: MQLONG) -> impl Iterator<Item = &str> {
93 self.iter()
94 .take_while(move |(v, ..)| *v <= value)
95 .filter_map(move |(v, name)| (*v == value).then_some(*name))
96 }
97
98 fn by_name(&self, name: &str) -> Option<MQLONG> {
99 self.iter().find_map(|(value, n)| (*n == name).then_some(*value))
100 }
101
102 fn all(&self) -> impl Iterator<Item = ConstantItem<'_>> {
103 self.iter().copied()
104 }
105}
106
107pub trait HasMqNames {
108 fn mq_names(&self) -> impl Iterator<Item = &'static str>;
109 fn mq_primary_name(&self) -> Option<&'static str>;
110}
111
112impl<T: MqConstant + HasConstLookup> HasMqNames for T
113where
114 T::Value: TryInto<MQLONG>,
115{
116 fn mq_names(&self) -> impl Iterator<Item = &'static str> {
117 self.mq_value()
118 .try_into()
119 .map(|value| Self::const_lookup().by_value(value))
120 .into_iter()
121 .flatten()
122 }
123 fn mq_primary_name(&self) -> Option<&'static str> {
124 self.mq_names().next()
125 }
126}
127
128#[cfg(test)]
129#[cfg_attr(coverage_nightly, coverage(off))]
130mod tests {
131 use super::*;
132
133 const ZERO: LinearSource = ConstSource(&[], &[]);
134 const ONE: LinearSource = ConstSource(&[(1, "ONE")], &[]);
135 const ONEB: LinearSource = ConstSource(&[(1, "ONE")], &[(1, "ONEB"), (2, "TWO")]);
136
137 #[test]
138 fn const_source() {
139 assert_eq!(ZERO.by_name("TEST"), None);
140 assert_eq!(ONE.by_name("ONE"), Some(1));
141 assert_eq!(ONE.by_name("ZERO"), None);
142 assert_eq!(ONEB.by_name("ONEB"), Some(1));
143 assert_eq!(ONEB.by_name("THREE"), None);
144
145 assert_eq!(ONEB.by_value(1).collect::<Vec<_>>(), &["ONE", "ONEB"]);
146 assert_eq!(ONEB.by_value(0).collect::<Vec<_>>(), Vec::<&str>::new());
147 }
148}