1pub struct NS<'a> {
14 pub name: &'a str,
16 pub fn_name: &'a str,
18 pub code: i32,
20}
21
22pub const NS_MULT_BASE: i32 = 100_000_000;
25
26#[allow(dead_code)]
27pub const NS_WORK: NS<'static> = NS::new("OL-W", "ol_work", 1);
28#[allow(dead_code)]
29pub const NS_EDITION: NS<'static> = NS::new("OL-E", "ol_edition", 2);
30#[allow(dead_code)]
31pub const NS_LOC_REC: NS<'static> = NS::new("LOC", "loc_rec", 3);
32#[allow(dead_code)]
33pub const NS_GR_WORK: NS<'static> = NS::new("GR-W", "gr_work", 4);
34#[allow(dead_code)]
35pub const NS_GR_BOOK: NS<'static> = NS::new("GR-B", "gr_book", 5);
36#[allow(dead_code)]
37pub const NS_LOC_WORK: NS<'static> = NS::new("LOC-W", "loc_work", 6);
38#[allow(dead_code)]
39pub const NS_LOC_INSTANCE: NS<'static> = NS::new("LOC-I", "loc_instance", 7);
40#[allow(dead_code)]
41pub const NS_ISBN: NS<'static> = NS::new("ISBN", "isbn", 9);
42
43const NAMESPACES: &'static [&'static NS<'static>] = &[
44 &NS_WORK,
45 &NS_EDITION,
46 &NS_LOC_REC,
47 &NS_GR_WORK,
48 &NS_GR_BOOK,
49 &NS_LOC_WORK,
50 &NS_LOC_INSTANCE,
51 &NS_ISBN,
52];
53
54#[cfg(test)]
55use quickcheck::quickcheck;
56
57impl<'a> NS<'a> {
58 const fn new(name: &'a str, fn_name: &'a str, code: i32) -> NS<'a> {
60 NS {
61 name,
62 fn_name,
63 code,
64 }
65 }
66
67 #[allow(dead_code)]
69 pub fn name(&'a self) -> &'a str {
70 self.name
71 }
72
73 pub fn code(&'a self) -> i32 {
75 self.code
76 }
77
78 pub fn base(&'a self) -> i32 {
81 self.code() * NS_MULT_BASE
82 }
83
84 #[allow(dead_code)]
86 pub fn to_code(&'a self, n: i32) -> i32 {
87 assert!(n >= 0);
88 assert!(n <= NS_MULT_BASE);
89 n + self.base()
90 }
91
92 pub fn from_code(&'a self, n: i32) -> Option<i32> {
94 let lo = self.base();
95 let hi = lo + NS_MULT_BASE;
96 if n >= lo && n < hi {
97 Some(n - lo)
98 } else {
99 None
100 }
101 }
102}
103
104impl NS<'static> {
105 pub fn by_name(name: &str) -> Option<&'static NS<'static>> {
106 for ns in NAMESPACES {
107 if ns.name() == name {
108 return Some(ns);
109 }
110 }
111
112 None
113 }
114}
115
116pub fn ns_of_book_code(code: i32) -> Option<&'static NS<'static>> {
118 let pfx = code / NS_MULT_BASE;
119 if pfx >= 1 {
120 for ns in NAMESPACES {
121 if ns.code() == pfx {
122 return Some(ns);
123 }
124 }
125 }
126
127 None
128}
129
130#[cfg(test)]
131quickcheck! {
132 fn prop_code_looks_up(code: i32) -> bool {
133 if let Some(ns) = ns_of_book_code(code) {
134 let bc = code % NS_MULT_BASE;
136 ns.to_code(bc) == code
137 } else {
138 code < NS_MULT_BASE || code > 10*NS_MULT_BASE || code / NS_MULT_BASE == 8
140 }
141 }
142}
143
144#[test]
145fn test_to_code() {
146 let n = 42;
147 let code = NS_LOC_REC.to_code(n);
148 assert_eq!(code / NS_MULT_BASE, NS_LOC_REC.code());
149}
150
151#[test]
152fn test_from_code() {
153 let n = 42;
154 let code = NS_LOC_REC.to_code(n);
155 assert_eq!(NS_LOC_REC.from_code(code), Some(n));
156 assert_eq!(NS_EDITION.from_code(code), None);
157 assert_eq!(NS_ISBN.from_code(code), None);
158}