bos_books_codes/
lib.rs

1#![allow(non_snake_case)]
2// #![allow(unused)]
3
4// use std::path::Path;
5// use std::fs::File;
6use std::collections::HashMap;
7use std::error::Error;
8// use std::fs;
9
10// use lazy_static::lazy_static;
11
12use serde::Deserialize;
13// use serde::Deserialize;
14// use serde::de::Error;
15//use serde_json::{Map, Value};
16
17#[derive(Debug, Deserialize, Clone)]
18#[serde(untagged)]
19enum StringOrListOfStrings {
20    Abbreviation(String),
21    ListOfAbbreviations(Vec<String>),
22}
23
24#[derive(Debug, Deserialize, Clone)]
25struct ReferenceNumber(u16); // 1..999
26
27#[derive(Debug, Deserialize, Clone)]
28struct AbbreviationEntry {
29    // for Bibleworks, Byzantine
30    referenceNumber: ReferenceNumber,
31    referenceAbbreviation: String,
32}
33
34#[derive(Debug, Deserialize, Clone)]
35struct AbbreviationOrAbbreviationsEntry {
36    // for SBL, OSIS, Sword, CCEL, NET, Drupal
37    referenceNumber: ReferenceNumber,
38    referenceAbbreviationOrAbbreviations: StringOrListOfStrings,
39}
40
41#[derive(Debug, Deserialize, Clone)]
42struct USFMAbbreviationEntry {
43    referenceNumber: ReferenceNumber,
44    USFMAbbreviationOrAbbreviations: StringOrListOfStrings,
45    USFMNumberStringOrStrings: Option<StringOrListOfStrings>,
46}
47
48#[derive(Debug, Deserialize, Clone)]
49struct USFMNumberEntry {
50    referenceNumber: ReferenceNumber,
51    referenceAbbreviationOrAbbreviations: StringOrListOfStrings,
52    USFMAbbreviationOrAbbreviations: StringOrListOfStrings,
53}
54
55#[derive(Debug, Deserialize, Clone)]
56struct GeneralNumberEntry {
57    // for USX, unboundBible, Bibledit
58    referenceNumber: ReferenceNumber,
59    referenceAbbreviation: String,
60    USFMAbbreviation: String,
61}
62
63#[derive(Debug, Deserialize, Clone)]
64struct ReferenceAbbreviationEntry {
65    referenceNumber: ReferenceNumber,
66    originalLanguageCode: String,
67    bookName: String,
68    shortAbbreviation: Option<String>,
69    SBLAbbreviation: Option<String>,
70    OSISAbbreviation: Option<String>,
71    SwordAbbreviation: Option<String>,
72    CCELNumberString: Option<String>,
73    USFMAbbreviation: Option<String>,
74    USFMNumberString: Option<String>,
75    USXNumberString: Option<String>,
76    UnboundCodeString: Option<String>,
77    BibleditNumberString: Option<String>,
78    NETBibleAbbreviation: Option<String>,
79    DrupalBibleAbbreviation: Option<String>,
80    ByzantineAbbreviation: Option<String>,
81    numExpectedChaptersString: Option<String>,
82    possibleAlternativeBooksList: Option<Vec<String>>,
83    bookNameEnglishGuide: String,
84    typicalSection: String,
85}
86
87#[derive(Debug, Deserialize, Clone)]
88struct ReferenceNumberEntry {
89    referenceAbbreviation: String,
90    originalLanguageCode: String,
91    bookName: String,
92    shortAbbreviation: Option<String>,
93    SBLAbbreviation: Option<String>,
94    OSISAbbreviation: Option<String>,
95    SwordAbbreviation: Option<String>,
96    CCELNumberString: Option<String>,
97    USFMAbbreviation: Option<String>,
98    USFMNumberString: Option<String>,
99    USXNumberString: Option<String>,
100    UnboundCodeString: Option<String>,
101    BibleditNumberString: Option<String>,
102    NETBibleAbbreviation: Option<String>,
103    DrupalBibleAbbreviation: Option<String>,
104    ByzantineAbbreviation: Option<String>,
105    numExpectedChaptersString: Option<String>,
106    possibleAlternativeBooksList: Option<Vec<String>>,
107    bookNameEnglishGuide: String,
108    typicalSection: String,
109}
110
111#[derive(Debug, Deserialize, Clone)]
112pub struct BibleBooksCodes { // This is public so we can return it
113    BibleWorksAbbreviationDict: HashMap<String, AbbreviationEntry>,
114    BibleditNumberDict: HashMap<String, GeneralNumberEntry>,
115    ByzantineAbbreviationDict: HashMap<String, AbbreviationEntry>,
116    CCELDict: HashMap<String, AbbreviationOrAbbreviationsEntry>,
117    DrupalBibleAbbreviationDict: HashMap<String, AbbreviationOrAbbreviationsEntry>,
118    EnglishNameDict: HashMap<String, AbbreviationEntry>,
119    NETBibleAbbreviationDict: HashMap<String, AbbreviationOrAbbreviationsEntry>,
120    OSISAbbreviationDict: HashMap<String, AbbreviationOrAbbreviationsEntry>,
121    SBLAbbreviationDict: HashMap<String, AbbreviationOrAbbreviationsEntry>,
122    SwordAbbreviationDict: HashMap<String, AbbreviationOrAbbreviationsEntry>,
123    USFMAbbreviationDict: HashMap<String, USFMAbbreviationEntry>,
124    USFMNumberDict: HashMap<String, USFMNumberEntry>,
125    USXNumberDict: HashMap<String, GeneralNumberEntry>,
126    UnboundCodeDict: HashMap<String, GeneralNumberEntry>,
127    allAbbreviationsDict: HashMap<String, String>,
128    referenceAbbreviationDict: HashMap<String, ReferenceAbbreviationEntry>,
129    referenceNumberDict: HashMap<String, ReferenceNumberEntry>,
130}
131
132impl BibleBooksCodes {
133    pub fn usfm_to_bbb(&self, usfm_bbb: &str) -> Result<String, Box<dyn Error>> {
134        // println!("usfm_to_bbb for {:?}", &usfm_bbb);
135        if ! &self.USFMAbbreviationDict.contains_key(usfm_bbb) {
136            return Err("Invalid USFM abbreviation: '".to_owned() + usfm_bbb + "'")?; // I never actually figured out why I need the question mark?
137        }
138        let bbbStringOrListOfStrings = &self.USFMAbbreviationDict[usfm_bbb].USFMAbbreviationOrAbbreviations;
139        match bbbStringOrListOfStrings {
140            StringOrListOfStrings::Abbreviation(bbb) => Ok(bbb.to_string()),
141            StringOrListOfStrings::ListOfAbbreviations(bbb_list) => Ok(bbb_list[0].to_string()),
142        }
143    }
144
145    pub fn usfm_num_to_usfm_abbrev(&self, usfm_num_str: &str) -> Result<String, Box<dyn Error>> {
146        // println!("usfm_num_to_usfm_abbrev for {:?}", usfm_num_str);
147        if ! &self.USFMNumberDict.contains_key(usfm_num_str) {
148            return Err("Invalid USFM number: '".to_owned() + &usfm_num_str + "'")?; // I never actually figured out why I need the question mark?
149        }
150        let bbbStringOrListOfStrings = &self.USFMNumberDict[usfm_num_str].USFMAbbreviationOrAbbreviations;
151        match bbbStringOrListOfStrings {
152            StringOrListOfStrings::Abbreviation(bbb) => Ok(bbb.to_string()),
153            StringOrListOfStrings::ListOfAbbreviations(bbb_list) => Ok(bbb_list[0].to_string()),
154        }
155    }
156
157    pub fn usfm_num_to_bbb(&self, usfm_num_str: &str) -> Result<String, Box<dyn Error>> {
158        // println!("usfm_num_to_bbb for {:?}", usfm_num_str);
159        if ! &self.USFMNumberDict.contains_key(usfm_num_str) {
160            return Err("Invalid USFM number: '".to_owned() + &usfm_num_str + "'")?; // I never actually figured out why I need the question mark?
161        }
162        let bbbStringOrListOfStrings = &self.USFMNumberDict[usfm_num_str].referenceAbbreviationOrAbbreviations;
163        match bbbStringOrListOfStrings {
164            StringOrListOfStrings::Abbreviation(bbb) => Ok(bbb.to_string()),
165            StringOrListOfStrings::ListOfAbbreviations(bbb_list) => Ok(bbb_list[0].to_string()),
166        }
167    }
168}
169
170#[cfg(test)]
171mod tests {
172    #[test]
173
174fn it_works() {
175        use crate::{load_from_json, BibleBooksCodes};
176        // let data_folderpath = Path::new("DataFiles/");
177        let data_folderpath = String::from("../");
178        let bible_books_codes: BibleBooksCodes = load_from_json(&data_folderpath).unwrap();
179        assert_eq!(bible_books_codes.referenceNumberDict["42"].referenceAbbreviation, "LUK");
180        assert_eq!(bible_books_codes.usfm_to_bbb("JAS").unwrap(), "JAM");
181        assert_eq!(bible_books_codes.usfm_num_to_usfm_abbrev("41").unwrap(), "Mat");
182        assert_eq!(bible_books_codes.usfm_num_to_bbb("42").unwrap(), "MRK");
183    }
184}
185
186
187// fn print_type_of<T>(_: &T) {
188//     println!("{}", std::any::type_name::<T>())
189// }
190
191
192pub fn load_from_json(data_folderpath: &String) -> Result<BibleBooksCodes, Box<dyn Error>> {
193    println!("  In bos_books_codes::load_from_json()…");
194
195    // NOTE: The following code doesn't work in a crate because we can't access the src/ folder.
196    // let filepath = data_folderpath.to_owned() + "derivedFormats/BibleBooksCodes_Tables.json";
197    // let mut owned_string: String = "Something went wrong reading the Books Codes JSON file: ".to_owned();
198    // owned_string.push_str(&filepath);
199    // let the_file_contents = fs::read_to_string(filepath).expect(&owned_string);
200    let the_file_contents = include_str!("BibleBooksCodes_Tables.json");
201    let bible_books_codes: BibleBooksCodes =
202        serde_json::from_str(&the_file_contents).expect("Books codes JSON was not well-formatted");
203    println!("    Loaded Bible books codes data for {:?} books.",
204        bible_books_codes.referenceNumberDict.len());
205    println!("      Book 42 is {:?}: {:?}",
206        bible_books_codes.referenceNumberDict["42"].referenceAbbreviation,
207        bible_books_codes.referenceNumberDict["42"].bookNameEnglishGuide);
208
209    Ok(bible_books_codes)
210}