botanical_latin/
lib.rs

1use serde::{Deserialize, Deserializer};
2use std::collections::HashMap;
3use std::error::Error;
4
5pub type NounMap = HashMap<String, NounRecord>;
6pub type AdjectiveMap = HashMap<String, AdjectiveRecord>;
7pub type VerbMap = HashMap<String, VerbRecord>;
8pub type Verb = String;
9
10#[derive(Debug, Deserialize, Clone, Default)]
11pub struct Latin {
12    pub noun_map: NounMap,
13    pub adj_map: AdjectiveMap,
14    pub verb_map: VerbMap,
15}
16
17pub struct ComplexNoun {
18    //   pub case: Case,
19    //  pub number: Number,
20    pub head_noun: String,
21    pub adjective: Vec<String>,
22    pub adposition_noun: Vec<String>,
23}
24
25impl Default for ComplexNoun {
26    fn default() -> Self {
27        Self {
28            head_noun: "exemplum".into(),
29            adposition_noun: Vec::new(),
30            adjective: Vec::new(),
31        }
32    }
33}
34
35#[derive(Debug, Deserialize, Clone, Default)]
36pub struct NounRecord {
37    pub word: String,
38    pub nom_sg: String,
39    pub gen_sg: String,
40    pub dat_sg: String,
41    pub acc_sg: String,
42    pub abl_sg: String,
43    pub voc_sg: String,
44    pub loc_sg: String,
45    pub nom_pl: String,
46    pub gen_pl: String,
47    pub dat_pl: String,
48    pub acc_pl: String,
49    pub abl_pl: String,
50    pub voc_pl: String,
51    pub loc_pl: String,
52
53    #[serde(deserialize_with = "deserialize_gender")]
54    pub gender: Gender,
55}
56
57#[derive(Debug, PartialEq, Clone)]
58pub enum Mood {
59    Indicative,
60    Subjunctive,
61    Imperative,
62    Infinitive,
63    Participle,
64    VerbalNoun,
65}
66
67#[derive(Debug, PartialEq, Clone)]
68pub enum Voice {
69    Active,
70    Passive,
71}
72#[derive(Debug, PartialEq, Clone)]
73pub enum Tense {
74    Present,
75    Imperfect,
76    Future,
77    Perfect,
78    Pluperfect,
79    FuturePerfect,
80}
81
82impl Default for Gender {
83    fn default() -> Gender {
84        Gender::Masculine
85    }
86}
87
88//word,canonical,present_infinitive,perfect_active,supine,conjugation,irregular
89#[derive(Debug, Deserialize, Clone, Default)]
90pub struct VerbRecord {
91    pub word: String,
92    pub canonical: String,
93    pub present_infinitive: String,
94    pub perfect_active: String,
95    pub supine: String,
96    pub indicative_active_present_singular_first: String,
97    pub indicative_active_present_singular_second: String,
98    pub indicative_active_present_singular_third: String,
99    pub indicative_active_present_plural_first: String,
100    pub indicative_active_present_plural_second: String,
101    pub indicative_active_present_plural_third: String,
102    pub indicative_active_imperfect_singular_first: String,
103    pub indicative_active_imperfect_singular_second: String,
104    pub indicative_active_imperfect_singular_third: String,
105    pub indicative_active_imperfect_plural_first: String,
106    pub indicative_active_imperfect_plural_second: String,
107    pub indicative_active_imperfect_plural_third: String,
108    pub indicative_active_future_singular_first: String,
109    pub indicative_active_future_singular_second: String,
110    pub indicative_active_future_singular_third: String,
111    pub indicative_active_future_plural_first: String,
112    pub indicative_active_future_plural_second: String,
113    pub indicative_active_future_plural_third: String,
114    pub indicative_active_perfect_singular_first: String,
115    pub indicative_active_perfect_singular_second: String,
116    pub indicative_active_perfect_singular_third: String,
117    pub indicative_active_perfect_plural_first: String,
118    pub indicative_active_perfect_plural_second: String,
119    pub indicative_active_perfect_plural_third: String,
120    pub indicative_active_pluperfect_singular_first: String,
121    pub indicative_active_pluperfect_singular_second: String,
122    pub indicative_active_pluperfect_singular_third: String,
123    pub indicative_active_pluperfect_plural_first: String,
124    pub indicative_active_pluperfect_plural_second: String,
125    pub indicative_active_pluperfect_plural_third: String,
126}
127
128//word,feminine,neuter,comparative,superlative,adverb,declension,adj_stem
129#[derive(Debug, Deserialize, Clone, Default)]
130pub struct AdjectiveRecord {
131    pub word: String,
132
133    pub comparative: String,
134    pub superlative: String,
135    pub adverb: String,
136    pub nom_sg_masc: String,
137    pub gen_sg_masc: String,
138    pub dat_sg_masc: String,
139    pub acc_sg_masc: String,
140    pub abl_sg_masc: String,
141    pub nom_sg_fem: String,
142    pub gen_sg_fem: String,
143    pub dat_sg_fem: String,
144    pub acc_sg_fem: String,
145    pub abl_sg_fem: String,
146    pub nom_sg_neut: String,
147    pub gen_sg_neut: String,
148    pub dat_sg_neut: String,
149    pub acc_sg_neut: String,
150    pub abl_sg_neut: String,
151    pub nom_pl_masc: String,
152    pub gen_pl_masc: String,
153    pub dat_pl_masc: String,
154    pub acc_pl_masc: String,
155    pub abl_pl_masc: String,
156    pub nom_pl_fem: String,
157    pub gen_pl_fem: String,
158    pub dat_pl_fem: String,
159    pub acc_pl_fem: String,
160    pub abl_pl_fem: String,
161    pub nom_pl_neut: String,
162    pub gen_pl_neut: String,
163    pub dat_pl_neut: String,
164    pub acc_pl_neut: String,
165    pub abl_pl_neut: String,
166}
167
168fn deserialize_gender<'de, D>(deserializer: D) -> Result<Gender, D::Error>
169where
170    D: Deserializer<'de>,
171{
172    let s: String = String::deserialize(deserializer)?;
173    match s.as_str() {
174        "m" => Ok(Gender::Masculine),
175        "f" => Ok(Gender::Feminine),
176        "n" => Ok(Gender::Neuter),
177        _ => Err(serde::de::Error::custom("unknown gender")),
178    }
179}
180
181fn deserialize_pluralia<'de, D>(deserializer: D) -> Result<bool, D::Error>
182where
183    D: Deserializer<'de>,
184{
185    let s: String = String::deserialize(deserializer)?;
186    match s.as_str() {
187        "fa" => Ok(false),
188        "tr" => Ok(true),
189
190        _ => Err(serde::de::Error::custom("unknown pluralia")),
191    }
192}
193
194#[derive(Debug, PartialEq, Clone)]
195pub enum Gender {
196    Masculine,
197    Feminine,
198    Neuter,
199}
200#[derive(Debug, PartialEq, Clone)]
201pub enum Case {
202    Nom,
203    Gen,
204    Dat,
205    Acc,
206    Abl,
207    Loc,
208    Voc,
209}
210
211#[derive(Debug, PartialEq, Clone)]
212pub struct CaseEndings {
213    pub gender: Gender,
214    pub nom_sg: &'static str,
215    pub acc_sg: &'static str,
216    pub gen_sg: &'static str,
217    pub dat_sg: &'static str,
218    pub abl_sg: &'static str,
219
220    pub nom_pl: &'static str,
221    pub acc_pl: &'static str,
222    pub gen_pl: &'static str,
223    pub dat_pl: &'static str,
224    pub abl_pl: &'static str,
225}
226
227impl CaseEndings {
228    pub fn ending(&self, case: &Case, number: &Number) -> &str {
229        match number {
230            Number::Singular => match case {
231                Case::Nom => self.nom_sg,
232                Case::Acc => self.acc_sg,
233                Case::Gen => self.gen_sg,
234                Case::Dat => self.dat_sg,
235                Case::Abl => self.abl_sg,
236                Case::Loc => self.abl_sg,
237                Case::Voc => self.nom_sg,
238            },
239            Number::Plural => match case {
240                Case::Nom => self.nom_pl,
241                Case::Acc => self.acc_pl,
242                Case::Gen => self.gen_pl,
243                Case::Dat => self.dat_pl,
244                Case::Abl => self.abl_pl,
245                Case::Loc => self.abl_pl,
246                Case::Voc => self.nom_pl,
247            },
248        }
249    }
250}
251
252pub const ONE_LETTER_ENDINGS: [CaseEndings; 4] = [
253    A_DECLENSION_ENDINGS,
254    E_DECLENSION_ENDINGS,
255    O_DECLENSION_ENDINGS,
256    U_DECLENSION_ENDINGS,
257];
258pub const TWO_LETTER_ENDINGS: [CaseEndings; 23] = [
259    AL_DECLENSION_ENDINGS,
260    AR_DECLENSION_ENDINGS,
261    AR_DECLENSION_ENDINGS,
262    AS_DECLENSION_ENDINGS,
263    AX_DECLENSION_ENDINGS,
264    EN_DECLENSION_ENDINGS,
265    ER_DECLENSION_ENDINGS,
266    ES_DECLENSION_ENDINGS,
267    EX_DECLENSION_ENDINGS,
268    ON_DECLENSION_ENDINGS,
269    OR_DECLENSION_ENDINGS,
270    OS_DECLENSION_ENDINGS,
271    UM_DECLENSION_ENDINGS,
272    US_DECLENSION_ENDINGS,
273    UT_DECLENSION_ENDINGS,
274    UX_DECLENSION_ENDINGS,
275    MA_DECLENSION_ENDINGS,
276    YX_DECLENSION_ENDINGS,
277    YS_DECLENSION_ENDINGS,
278    NX_DECLENSION_ENDINGS,
279    MA_DECLENSION_ENDINGS,
280    IS_DECLENSION_ENDINGS,
281    IX_DECLENSION_ENDINGS,
282];
283
284pub const TEST_ENDINGS: CaseEndings = CaseEndings {
285    gender: Gender::Neuter,
286    nom_sg: "nom_sg",
287    acc_sg: "acc_sg",
288    gen_sg: "gen_sg",
289    dat_sg: "dat_sg",
290    abl_sg: "abl_sg",
291
292    nom_pl: "nom_pl",
293    acc_pl: "acc_pl",
294    gen_pl: "gen_pl",
295    dat_pl: "dat_pl",
296    abl_pl: "abl_pl",
297};
298
299pub const A_DECLENSION_ENDINGS: CaseEndings = CaseEndings {
300    gender: Gender::Feminine,
301    nom_sg: "a",
302    acc_sg: "am",
303    gen_sg: "ae",
304    dat_sg: "ae",
305    abl_sg: "a",
306
307    nom_pl: "ae",
308    acc_pl: "as",
309    gen_pl: "arum",
310    dat_pl: "is",
311    abl_pl: "is",
312};
313
314/*pub const RA_DECLENSION_ENDINGS: CaseEndings = CaseEndings {
315    gender: Gender::Feminine,
316    nom_sg: "ra",
317    acc_sg: "ram",
318    gen_sg: "rae",
319    dat_sg: "rae",
320    abl_sg: "ra",
321
322    nom_pl: "rae",
323    acc_pl: "ras",
324    gen_pl: "rarum",
325    dat_pl: "ris",
326    abl_pl: "ris",
327};
328 */
329pub const US_DECLENSION_ENDINGS: CaseEndings = CaseEndings {
330    gender: Gender::Masculine,
331    nom_sg: "us",
332    acc_sg: "um",
333    gen_sg: "i",
334    dat_sg: "o",
335    abl_sg: "o",
336
337    nom_pl: "i",
338    acc_pl: "os",
339    gen_pl: "orum",
340    dat_pl: "is",
341    abl_pl: "is",
342};
343
344pub const O_DECLENSION_ENDINGS: CaseEndings = CaseEndings {
345    gender: Gender::Masculine,
346    nom_sg: "o",
347    acc_sg: "onem",
348    gen_sg: "onis",
349    dat_sg: "oni",
350    abl_sg: "one",
351
352    nom_pl: "ones",
353    acc_pl: "ones",
354    gen_pl: "onum",
355    dat_pl: "onibus",
356    abl_pl: "onibus",
357};
358
359pub const ON_DECLENSION_ENDINGS: CaseEndings = CaseEndings {
360    gender: Gender::Masculine,
361    nom_sg: "on",
362    acc_sg: "ontem",
363    gen_sg: "ontis",
364    dat_sg: "onti",
365    abl_sg: "onte",
366
367    nom_pl: "ontes",
368    acc_pl: "ontes",
369    gen_pl: "ontum",
370    dat_pl: "ontibus",
371    abl_pl: "ontibus",
372};
373
374pub const UT_DECLENSION_ENDINGS: CaseEndings = CaseEndings {
375    gender: Gender::Neuter,
376    nom_sg: "ut",
377    acc_sg: "ut",
378    gen_sg: "itis",
379    dat_sg: "iti",
380    abl_sg: "ite",
381
382    nom_pl: "ita",
383    acc_pl: "ita",
384    gen_pl: "itum",
385    dat_pl: "itibus",
386    abl_pl: "itibus",
387};
388
389pub const OR_DECLENSION_ENDINGS: CaseEndings = CaseEndings {
390    gender: Gender::Masculine,
391    nom_sg: "or",
392    acc_sg: "orem",
393    gen_sg: "oris",
394    dat_sg: "ori",
395    abl_sg: "ore",
396
397    nom_pl: "ores",
398    acc_pl: "ores",
399    gen_pl: "orum",
400    dat_pl: "oribus",
401    abl_pl: "oribus",
402};
403
404pub const OR_ADJ_NEUTER_ENDINGS: CaseEndings = CaseEndings {
405    gender: Gender::Masculine,
406    nom_sg: "or",
407    acc_sg: "or",
408    gen_sg: "oris",
409    dat_sg: "ori",
410    abl_sg: "ori",
411
412    nom_pl: "oria",
413    acc_pl: "oria",
414    gen_pl: "orium",
415    dat_pl: "oribus",
416    abl_pl: "oribus",
417};
418
419pub const OS_DECLENSION_ENDINGS: CaseEndings = CaseEndings {
420    gender: Gender::Masculine,
421    nom_sg: "os",
422    acc_sg: "orem",
423    gen_sg: "oris",
424    dat_sg: "ori",
425    abl_sg: "ore",
426
427    nom_pl: "ores",
428    acc_pl: "ores",
429    gen_pl: "orum",
430    dat_pl: "oribus",
431    abl_pl: "oribus",
432};
433pub const S_DECLENSION_ENDINGS: CaseEndings = CaseEndings {
434    gender: Gender::Masculine,
435    nom_sg: "s",
436    acc_sg: "tem",
437    gen_sg: "tis",
438    dat_sg: "ti",
439    abl_sg: "te",
440
441    nom_pl: "tes",
442    acc_pl: "tes",
443    gen_pl: "tium",
444    dat_pl: "tibus",
445    abl_pl: "tibus",
446};
447
448pub const S_ADJ_NEUTER_ENDINGS: CaseEndings = CaseEndings {
449    gender: Gender::Masculine,
450    nom_sg: "s",
451    acc_sg: "s",
452    gen_sg: "tis",
453    dat_sg: "ti",
454    abl_sg: "te",
455
456    nom_pl: "tia",
457    acc_pl: "tia",
458    gen_pl: "tium",
459    dat_pl: "tibus",
460    abl_pl: "tibus",
461};
462
463pub const UM_DECLENSION_ENDINGS: CaseEndings = CaseEndings {
464    gender: Gender::Neuter,
465    nom_sg: "um",
466    acc_sg: "um",
467    gen_sg: "i",
468    dat_sg: "o",
469    abl_sg: "o",
470
471    nom_pl: "a",
472    acc_pl: "a",
473    gen_pl: "orum",
474    dat_pl: "is",
475    abl_pl: "is",
476};
477
478/*pub const RUM_DECLENSION_ENDINGS: CaseEndings = CaseEndings {
479    gender: Gender::Neuter,
480    nom_sg: "rum",
481    acc_sg: "rum",
482    gen_sg: "ri",
483    dat_sg: "ro",
484    abl_sg: "ro",
485
486    nom_pl: "ra",
487    acc_pl: "ra",
488    gen_pl: "rorum",
489    dat_pl: "ris",
490    abl_pl: "ris",
491}; */
492
493pub const U_DECLENSION_ENDINGS: CaseEndings = CaseEndings {
494    gender: Gender::Neuter,
495    nom_sg: "u",
496    acc_sg: "u",
497    gen_sg: "us",
498    dat_sg: "ui",
499    abl_sg: "u",
500
501    nom_pl: "ua",
502    acc_pl: "ua",
503    gen_pl: "uum",
504    dat_pl: "uibus",
505    abl_pl: "uibus",
506};
507
508pub const ER_DECLENSION_ENDINGS: CaseEndings = CaseEndings {
509    gender: Gender::Masculine,
510    nom_sg: "er",
511    acc_sg: "er",
512    gen_sg: "eris",
513    dat_sg: "eri",
514    abl_sg: "ere",
515
516    nom_pl: "era",
517    acc_pl: "era",
518    gen_pl: "erum",
519    dat_pl: "eribus",
520    abl_pl: "eribus",
521};
522
523pub const ER_ADJECTIVE_MASC_ENDINGS: CaseEndings = CaseEndings {
524    gender: Gender::Masculine,
525    nom_sg: "",
526    acc_sg: "um",
527    gen_sg: "i",
528    dat_sg: "o",
529    abl_sg: "o",
530
531    nom_pl: "i",
532    acc_pl: "os",
533    gen_pl: "orum",
534    dat_pl: "is",
535    abl_pl: "is",
536};
537
538pub const AL_DECLENSION_ENDINGS: CaseEndings = CaseEndings {
539    gender: Gender::Neuter,
540    nom_sg: "al",
541    acc_sg: "al",
542    gen_sg: "alis",
543    dat_sg: "ali",
544    abl_sg: "ali",
545
546    nom_pl: "alia",
547    acc_pl: "alia",
548    gen_pl: "alium",
549    dat_pl: "alibus",
550    abl_pl: "alibus",
551};
552
553pub const AR_DECLENSION_ENDINGS: CaseEndings = CaseEndings {
554    gender: Gender::Neuter,
555    nom_sg: "ar",
556    acc_sg: "ar",
557    gen_sg: "aris",
558    dat_sg: "ari",
559    abl_sg: "ari",
560
561    nom_pl: "aria",
562    acc_pl: "aria",
563    gen_pl: "arium",
564    dat_pl: "aribus",
565    abl_pl: "aribus",
566};
567
568pub const AS_DECLENSION_ENDINGS: CaseEndings = CaseEndings {
569    gender: Gender::Feminine,
570    nom_sg: "as",
571    acc_sg: "atem",
572    gen_sg: "atis",
573    dat_sg: "ati",
574    abl_sg: "ate",
575
576    nom_pl: "ates",
577    acc_pl: "ates",
578    gen_pl: "atum",
579    dat_pl: "atibus",
580    abl_pl: "atibus",
581};
582
583pub const AX_DECLENSION_ENDINGS: CaseEndings = CaseEndings {
584    gender: Gender::Feminine,
585    nom_sg: "ax",
586    acc_sg: "acem",
587    gen_sg: "acis",
588    dat_sg: "aci",
589    abl_sg: "ace",
590
591    nom_pl: "aces",
592    acc_pl: "aces",
593    gen_pl: "acum",
594    dat_pl: "acibus",
595    abl_pl: "acibus",
596};
597
598pub const IX_DECLENSION_ENDINGS: CaseEndings = CaseEndings {
599    gender: Gender::Feminine,
600    nom_sg: "ix",
601    acc_sg: "icem",
602    gen_sg: "icis",
603    dat_sg: "ici",
604    abl_sg: "ice",
605
606    nom_pl: "ices",
607    acc_pl: "ices",
608    gen_pl: "icum",
609    dat_pl: "icibus",
610    abl_pl: "icibus",
611};
612pub const YX_DECLENSION_ENDINGS: CaseEndings = CaseEndings {
613    gender: Gender::Feminine,
614    nom_sg: "yx",
615    acc_sg: "ycem",
616    gen_sg: "ycis",
617    dat_sg: "yci",
618    abl_sg: "yce",
619
620    nom_pl: "yces",
621    acc_pl: "yces",
622    gen_pl: "ycum",
623    dat_pl: "ycibus",
624    abl_pl: "ycibus",
625};
626
627pub const YS_DECLENSION_ENDINGS: CaseEndings = CaseEndings {
628    gender: Gender::Masculine,
629    nom_sg: "ys",
630    acc_sg: "ydem",
631    gen_sg: "ydis",
632    dat_sg: "ydi",
633    abl_sg: "yde",
634
635    nom_pl: "ydes",
636    acc_pl: "ydes",
637    gen_pl: "ydum",
638    dat_pl: "ydibus",
639    abl_pl: "ydibus",
640};
641
642pub const UX_DECLENSION_ENDINGS: CaseEndings = CaseEndings {
643    gender: Gender::Feminine,
644    nom_sg: "ux",
645    acc_sg: "ucem",
646    gen_sg: "ucis",
647    dat_sg: "uci",
648    abl_sg: "uce",
649
650    nom_pl: "uces",
651    acc_pl: "uces",
652    gen_pl: "ucum",
653    dat_pl: "ucibus",
654    abl_pl: "ucibus",
655};
656
657pub const NX_DECLENSION_ENDINGS: CaseEndings = CaseEndings {
658    gender: Gender::Feminine,
659    nom_sg: "nx",
660    acc_sg: "ngem",
661    gen_sg: "ngis",
662    dat_sg: "ngi",
663    abl_sg: "nge",
664
665    nom_pl: "nges",
666    acc_pl: "nges",
667    gen_pl: "ngium",
668    dat_pl: "ngibus",
669    abl_pl: "ngibus",
670};
671
672pub const IS_DECLENSION_ENDINGS: CaseEndings = CaseEndings {
673    gender: Gender::Masculine,
674    nom_sg: "is",
675    acc_sg: "em",
676    gen_sg: "is",
677    dat_sg: "i",
678    abl_sg: "e",
679
680    nom_pl: "es",
681    acc_pl: "es",
682    gen_pl: "ium",
683    dat_pl: "ibus",
684    abl_pl: "ibus",
685};
686
687pub const IS_ADJECTIVE_MASC_ENDINGS: CaseEndings = CaseEndings {
688    gender: Gender::Masculine,
689    nom_sg: "is",
690    acc_sg: "em",
691    gen_sg: "is",
692    dat_sg: "i",
693    abl_sg: "i",
694
695    nom_pl: "es",
696    acc_pl: "es",
697    gen_pl: "ium",
698    dat_pl: "ibus",
699    abl_pl: "ibus",
700};
701
702pub const EX_DECLENSION_ENDINGS: CaseEndings = CaseEndings {
703    gender: Gender::Masculine,
704    nom_sg: "ex",
705    acc_sg: "icem",
706    gen_sg: "icis",
707    dat_sg: "ici",
708    abl_sg: "ice",
709
710    nom_pl: "ices",
711    acc_pl: "ices",
712    gen_pl: "icum",
713    dat_pl: "icibus",
714    abl_pl: "icibus",
715};
716
717pub const EX_ADJECTIVE_MASC_ENDINGS: CaseEndings = CaseEndings {
718    gender: Gender::Masculine,
719    nom_sg: "ex",
720    acc_sg: "icem",
721    gen_sg: "icis",
722    dat_sg: "ici",
723    abl_sg: "ici",
724
725    nom_pl: "ices",
726    acc_pl: "ices",
727    gen_pl: "icium",
728    dat_pl: "icibus",
729    abl_pl: "icibus",
730};
731
732pub const EX_ADJECTIVE_NEUT_ENDINGS: CaseEndings = CaseEndings {
733    gender: Gender::Masculine,
734    nom_sg: "ex",
735    acc_sg: "ex",
736    gen_sg: "icis",
737    dat_sg: "ici",
738    abl_sg: "ici",
739
740    nom_pl: "icia",
741    acc_pl: "icia",
742    gen_pl: "icium",
743    dat_pl: "icibus",
744    abl_pl: "icibus",
745};
746
747pub const E_DECLENSION_ENDINGS: CaseEndings = CaseEndings {
748    gender: Gender::Neuter,
749    nom_sg: "e",
750    acc_sg: "e",
751    gen_sg: "is",
752    dat_sg: "i",
753    abl_sg: "i",
754
755    nom_pl: "ia",
756    acc_pl: "ia",
757    gen_pl: "ium",
758    dat_pl: "ibus",
759    abl_pl: "ibus",
760};
761pub const EN_DECLENSION_ENDINGS: CaseEndings = CaseEndings {
762    gender: Gender::Neuter,
763    nom_sg: "en",
764    acc_sg: "en",
765    gen_sg: "inis",
766    dat_sg: "ini",
767    abl_sg: "ine",
768
769    nom_pl: "ina",
770    acc_pl: "ina",
771    gen_pl: "inum",
772    dat_pl: "inibus",
773    abl_pl: "inibus",
774};
775pub const ES_DECLENSION_ENDINGS: CaseEndings = CaseEndings {
776    gender: Gender::Feminine,
777    nom_sg: "es",
778    acc_sg: "em",
779    gen_sg: "ei",
780    dat_sg: "ei",
781    abl_sg: "e",
782
783    nom_pl: "es",
784    acc_pl: "es",
785    gen_pl: "erum",
786    dat_pl: "ebus",
787    abl_pl: "ebus",
788};
789
790pub const ES_ADJ_MASC_ENDINGS: CaseEndings = CaseEndings {
791    gender: Gender::Feminine,
792    nom_sg: "es",
793    acc_sg: "em",
794    gen_sg: "is",
795    dat_sg: "i",
796    abl_sg: "e",
797
798    nom_pl: "es",
799    acc_pl: "es",
800    gen_pl: "um",
801    dat_pl: "ibus",
802    abl_pl: "ibus",
803};
804pub const ES_ADJ_NEUT_ENDINGS: CaseEndings = CaseEndings {
805    gender: Gender::Feminine,
806    nom_sg: "es",
807    acc_sg: "em",
808    gen_sg: "is",
809    dat_sg: "i",
810    abl_sg: "e",
811
812    nom_pl: "es",
813    acc_pl: "es",
814    gen_pl: "um",
815    dat_pl: "ibus",
816    abl_pl: "ibus",
817};
818
819pub const MA_DECLENSION_ENDINGS: CaseEndings = CaseEndings {
820    gender: Gender::Neuter,
821    nom_sg: "ma",
822    acc_sg: "ma",
823    gen_sg: "matis",
824    dat_sg: "mati",
825    abl_sg: "mate",
826
827    nom_pl: "mata",
828    acc_pl: "mata",
829    gen_pl: "matum",
830    dat_pl: "matibus",
831    abl_pl: "matibus",
832};
833
834// have a possesive func, but reflexive person?
835#[derive(Debug, PartialEq, Clone)]
836pub enum Number {
837    Singular,
838    Plural,
839}
840
841pub type Noun = (String, Gender);
842pub type Adjective = String;
843
844#[derive(Debug, PartialEq, Clone)]
845pub enum Person {
846    First,
847    Second,
848    Third,
849}
850
851impl Latin {
852    pub fn guess_noun(word: &str, case: &Case, number: &Number) -> Noun {
853        let mut appended = Vec::from(TWO_LETTER_ENDINGS);
854        appended.append(&mut Vec::from(ONE_LETTER_ENDINGS));
855
856        for ce in &appended {
857            let nom_end = ce.nom_sg;
858
859            if word.ends_with(nom_end) {
860                let word_gender = &ce.gender;
861
862                let n = nom_end.len();
863
864                let mut word_stem = word.to_string();
865
866                if n <= word.len() {
867                    word_stem.truncate(word.len() - n);
868                    let ending = ce.ending(case, number);
869                    let merged = format!("{}{}", word_stem, ending);
870                    return (merged, word_gender.clone());
871                }
872            }
873        }
874
875        (word.to_string(), Gender::Masculine)
876    }
877
878    pub fn guess_adjective(word: &str, case: &Case, number: &Number, gender: &Gender) -> Adjective {
879        let mut word_stem = word.to_string();
880        word_stem.truncate(word_stem.len() - 2);
881
882        let mut masc_ends = &US_DECLENSION_ENDINGS;
883        let mut fem_ends = &A_DECLENSION_ENDINGS;
884        let mut neut_ends = &UM_DECLENSION_ENDINGS;
885
886        if word.ends_with("us") {
887            word_stem = word.to_string();
888            word_stem.truncate(word.len() - 2);
889
890            masc_ends = &US_DECLENSION_ENDINGS;
891            fem_ends = &A_DECLENSION_ENDINGS;
892            neut_ends = &UM_DECLENSION_ENDINGS;
893        } else if word.ends_with("er") {
894            word_stem = word.to_string();
895
896            masc_ends = &ER_ADJECTIVE_MASC_ENDINGS;
897        } else if word.ends_with("is") {
898            word_stem = word.to_string();
899            word_stem.truncate(word.len() - 2);
900
901            masc_ends = &IS_ADJECTIVE_MASC_ENDINGS;
902            fem_ends = &IS_ADJECTIVE_MASC_ENDINGS;
903            neut_ends = &E_DECLENSION_ENDINGS;
904        } else if word.ends_with("ex") {
905            word_stem = word.to_string();
906            word_stem.truncate(word.len() - 2);
907
908            masc_ends = &EX_ADJECTIVE_MASC_ENDINGS;
909            fem_ends = &EX_ADJECTIVE_MASC_ENDINGS;
910            neut_ends = &EX_ADJECTIVE_NEUT_ENDINGS;
911        } else if word.ends_with("or") {
912            word_stem = word.to_string();
913            word_stem.truncate(word.len() - 2);
914
915            masc_ends = &OR_DECLENSION_ENDINGS;
916            fem_ends = &OR_DECLENSION_ENDINGS;
917            neut_ends = &OR_ADJ_NEUTER_ENDINGS;
918        } else if word.ends_with("des") {
919            word_stem = word.to_string();
920            word_stem.truncate(word.len() - 2);
921
922            masc_ends = &ES_ADJ_MASC_ENDINGS;
923            fem_ends = &ES_ADJ_MASC_ENDINGS;
924            neut_ends = &ES_ADJ_NEUT_ENDINGS;
925        } else if word.ends_with("s") {
926            word_stem = word.to_string();
927            word_stem.truncate(word.len() - 1);
928
929            masc_ends = &S_DECLENSION_ENDINGS;
930            fem_ends = &S_DECLENSION_ENDINGS;
931            neut_ends = &S_ADJ_NEUTER_ENDINGS;
932        }
933
934        let ending = match gender {
935            Gender::Feminine => fem_ends.ending(case, number),
936            Gender::Masculine => masc_ends.ending(case, number),
937            Gender::Neuter => neut_ends.ending(case, number),
938        };
939
940        format!("{word_stem}{ending}")
941    }
942
943    pub fn complex_noun(
944        &self,
945        complex_nomen: &ComplexNoun,
946        case: &Case,
947        number: &Number,
948    ) -> String {
949        let noun = self.noun(&complex_nomen.head_noun, case, number);
950
951        let mut response = noun.0;
952
953        for adpos in &complex_nomen.adposition_noun {
954            let adposik = self.noun(adpos, case, number);
955            if adposik.0 != "" {
956                response = format!("{} {}", response, adposik.0);
957            }
958        }
959
960        for adj in &complex_nomen.adjective {
961            let adjik = self.adjective(adj, case, number, &noun.1);
962            if adjik != "" {
963                response = format!("{} {}", response, adjik);
964            }
965        }
966
967        response
968    }
969
970    pub fn noun(&self, word: &str, case: &Case, number: &Number) -> Noun {
971        let defik = NounRecord::default();
972
973        let recordik = self.noun_map.get(word);
974
975        match recordik {
976            Some(record) => {
977                let mut response = match number {
978                    Number::Singular => match case {
979                        Case::Nom => (record.nom_sg.clone(), record.gender.clone()),
980                        Case::Gen => (record.gen_sg.clone(), record.gender.clone()),
981                        Case::Dat => (record.dat_sg.clone(), record.gender.clone()),
982                        Case::Acc => (record.acc_sg.clone(), record.gender.clone()),
983                        Case::Abl => (record.abl_sg.clone(), record.gender.clone()),
984                        Case::Voc => (record.voc_sg.clone(), record.gender.clone()),
985                        Case::Loc => (record.loc_sg.clone(), record.gender.clone()),
986                    },
987                    Number::Plural => match case {
988                        Case::Nom => (record.nom_pl.clone(), record.gender.clone()),
989                        Case::Gen => (record.gen_pl.clone(), record.gender.clone()),
990                        Case::Dat => (record.dat_pl.clone(), record.gender.clone()),
991                        Case::Acc => (record.acc_pl.clone(), record.gender.clone()),
992                        Case::Abl => (record.abl_pl.clone(), record.gender.clone()),
993                        Case::Voc => (record.voc_pl.clone(), record.gender.clone()),
994                        Case::Loc => (record.loc_pl.clone(), record.gender.clone()),
995                    },
996                };
997
998                if case == &Case::Loc && (response.0 == "" || response.0 == "-") {
999                    response.0 = format!("{}", record.abl_sg.clone());
1000                }
1001
1002                if (response.0 == "" || response.0 == "-") {
1003                    response = Latin::guess_noun(word, case, number);
1004                }
1005
1006                response
1007            }
1008            None => Latin::guess_noun(word, case, number),
1009        }
1010    }
1011
1012    pub fn new(noun_path: String, adjective_path: String, verb_path: String) -> Self {
1013        Latin {
1014            noun_map: Latin::load_nouns_from_csv(noun_path),
1015            adj_map: Latin::load_adjectives_from_csv(adjective_path),
1016            verb_map: Latin::load_verbs_from_csv(verb_path),
1017        }
1018    }
1019
1020    //"nouns.csv"
1021    pub fn load_nouns_from_csv(path: String) -> NounMap {
1022        let mut nounmap = HashMap::new();
1023        let file_path: &str = path.as_str();
1024
1025        let mut rdr = csv::Reader::from_path(file_path).unwrap();
1026        for result in rdr.deserialize() {
1027            let record: NounRecord = result.unwrap();
1028
1029            nounmap.insert(record.word.clone(), record.clone());
1030
1031            //    //println!("{:?}", record);
1032        }
1033        nounmap
1034    }
1035    pub fn load_adjectives_from_csv(path: String) -> AdjectiveMap {
1036        let file_path: &str = path.as_str();
1037        let mut adjmap = HashMap::new();
1038        let mut rdr = csv::Reader::from_path(file_path).unwrap();
1039        for result in rdr.deserialize() {
1040            //   //println!("{:?}", result);
1041            let record: AdjectiveRecord = result.unwrap();
1042            adjmap.insert(record.word.clone(), record.clone());
1043            //  //println!("{:?}", record);
1044        }
1045        adjmap
1046    }
1047
1048    pub fn load_verbs_from_csv(path: String) -> VerbMap {
1049        let file_path: &str = path.as_str();
1050        let mut verbmap = HashMap::new();
1051        let mut rdr = csv::Reader::from_path(file_path).unwrap();
1052        for result in rdr.deserialize() {
1053            //println!("{:?}", result);
1054            let record: VerbRecord = result.unwrap();
1055            verbmap.insert(record.word.clone(), record.clone());
1056            //println!("{:?}", record);
1057        }
1058        verbmap
1059    }
1060
1061    pub fn adjective(
1062        &self,
1063        word: &str,
1064        case: &Case,
1065        number: &Number,
1066        gender: &Gender,
1067    ) -> Adjective {
1068        let defik = AdjectiveRecord::default();
1069
1070        let recordik = self.adj_map.get(word);
1071
1072        match recordik {
1073            Some(record) => match gender {
1074                Gender::Masculine => match number {
1075                    Number::Singular => match case {
1076                        Case::Nom => record.nom_sg_masc.clone(),
1077                        Case::Gen => record.gen_sg_masc.clone(),
1078                        Case::Dat => record.dat_sg_masc.clone(),
1079                        Case::Acc => record.acc_sg_masc.clone(),
1080                        Case::Abl => record.abl_sg_masc.clone(),
1081                        _ => record.abl_sg_masc.clone(),
1082                    },
1083                    Number::Plural => match case {
1084                        Case::Nom => record.nom_pl_masc.clone(),
1085                        Case::Gen => record.gen_pl_masc.clone(),
1086                        Case::Dat => record.dat_pl_masc.clone(),
1087                        Case::Acc => record.acc_pl_masc.clone(),
1088                        Case::Abl => record.abl_pl_masc.clone(),
1089                        _ => record.abl_pl_masc.clone(),
1090                    },
1091                },
1092                Gender::Feminine => match number {
1093                    Number::Singular => match case {
1094                        Case::Nom => record.nom_sg_fem.clone(),
1095                        Case::Gen => record.gen_sg_fem.clone(),
1096                        Case::Dat => record.dat_sg_fem.clone(),
1097                        Case::Acc => record.acc_sg_fem.clone(),
1098                        Case::Abl => record.abl_sg_fem.clone(),
1099                        _ => record.abl_sg_fem.clone(),
1100                    },
1101                    Number::Plural => match case {
1102                        Case::Nom => record.nom_pl_fem.clone(),
1103                        Case::Gen => record.gen_pl_fem.clone(),
1104                        Case::Dat => record.dat_pl_fem.clone(),
1105                        Case::Acc => record.acc_pl_fem.clone(),
1106                        Case::Abl => record.abl_pl_fem.clone(),
1107                        _ => record.abl_pl_fem.clone(),
1108                    },
1109                },
1110                Gender::Neuter => match number {
1111                    Number::Singular => match case {
1112                        Case::Nom => record.nom_sg_neut.clone(),
1113                        Case::Gen => record.gen_sg_neut.clone(),
1114                        Case::Dat => record.dat_sg_neut.clone(),
1115                        Case::Acc => record.acc_sg_neut.clone(),
1116                        Case::Abl => record.abl_sg_neut.clone(),
1117                        _ => record.abl_sg_neut.clone(),
1118                    },
1119                    Number::Plural => match case {
1120                        Case::Nom => record.nom_pl_neut.clone(),
1121                        Case::Gen => record.gen_pl_neut.clone(),
1122                        Case::Dat => record.dat_pl_neut.clone(),
1123                        Case::Acc => record.acc_pl_neut.clone(),
1124                        Case::Abl => record.abl_pl_neut.clone(),
1125                        _ => record.abl_pl_neut.clone(),
1126                    },
1127                },
1128            },
1129            None => Latin::guess_adjective(word, case, number, gender),
1130        }
1131    }
1132
1133    pub fn verb(
1134        &self,
1135        word: &str,
1136        mood: &Mood,
1137        voice: &Voice,
1138        tense: &Tense,
1139        number: &Number,
1140        person: &Person,
1141    ) -> Verb {
1142        let defik = VerbRecord::default();
1143
1144        let record = self.verb_map.get(word).unwrap_or(&defik);
1145
1146        match mood {
1147            Mood::Indicative => match voice {
1148                Voice::Active => match tense {
1149                    Tense::Present => match number {
1150                        Number::Singular => match person {
1151                            Person::First => {
1152                                record.indicative_active_present_singular_first.clone()
1153                            }
1154                            Person::Second => {
1155                                record.indicative_active_present_singular_second.clone()
1156                            }
1157                            Person::Third => {
1158                                record.indicative_active_present_singular_third.clone()
1159                            }
1160                        },
1161                        Number::Plural => match person {
1162                            Person::First => record.indicative_active_present_plural_first.clone(),
1163                            Person::Second => {
1164                                record.indicative_active_present_plural_second.clone()
1165                            }
1166                            Person::Third => record.indicative_active_present_plural_third.clone(),
1167                        },
1168                    },
1169                    Tense::Imperfect => match number {
1170                        Number::Singular => match person {
1171                            Person::First => {
1172                                record.indicative_active_imperfect_singular_first.clone()
1173                            }
1174                            Person::Second => {
1175                                record.indicative_active_imperfect_singular_second.clone()
1176                            }
1177                            Person::Third => {
1178                                record.indicative_active_imperfect_singular_third.clone()
1179                            }
1180                        },
1181                        Number::Plural => match person {
1182                            Person::First => {
1183                                record.indicative_active_imperfect_plural_first.clone()
1184                            }
1185                            Person::Second => {
1186                                record.indicative_active_imperfect_plural_second.clone()
1187                            }
1188                            Person::Third => {
1189                                record.indicative_active_imperfect_plural_third.clone()
1190                            }
1191                        },
1192                    },
1193                    Tense::Future => match number {
1194                        Number::Singular => match person {
1195                            Person::First => record.indicative_active_future_singular_first.clone(),
1196                            Person::Second => {
1197                                record.indicative_active_future_singular_second.clone()
1198                            }
1199                            Person::Third => record.indicative_active_future_singular_third.clone(),
1200                        },
1201                        Number::Plural => match person {
1202                            Person::First => record.indicative_active_future_plural_first.clone(),
1203                            Person::Second => record.indicative_active_future_plural_second.clone(),
1204                            Person::Third => record.indicative_active_future_plural_third.clone(),
1205                        },
1206                    },
1207                    Tense::Perfect => match number {
1208                        Number::Singular => match person {
1209                            Person::First => {
1210                                record.indicative_active_perfect_singular_first.clone()
1211                            }
1212                            Person::Second => {
1213                                record.indicative_active_perfect_singular_second.clone()
1214                            }
1215                            Person::Third => {
1216                                record.indicative_active_perfect_singular_third.clone()
1217                            }
1218                        },
1219                        Number::Plural => match person {
1220                            Person::First => record.indicative_active_perfect_plural_first.clone(),
1221                            Person::Second => {
1222                                record.indicative_active_perfect_plural_second.clone()
1223                            }
1224                            Person::Third => record.indicative_active_perfect_plural_third.clone(),
1225                        },
1226                    },
1227                    Tense::Pluperfect => match number {
1228                        Number::Singular => match person {
1229                            Person::First => {
1230                                record.indicative_active_pluperfect_singular_first.clone()
1231                            }
1232                            Person::Second => {
1233                                record.indicative_active_pluperfect_singular_second.clone()
1234                            }
1235                            Person::Third => {
1236                                record.indicative_active_pluperfect_singular_third.clone()
1237                            }
1238                        },
1239                        Number::Plural => match person {
1240                            Person::First => {
1241                                record.indicative_active_pluperfect_plural_first.clone()
1242                            }
1243                            Person::Second => {
1244                                record.indicative_active_pluperfect_plural_second.clone()
1245                            }
1246                            Person::Third => {
1247                                record.indicative_active_pluperfect_plural_third.clone()
1248                            }
1249                        },
1250                    },
1251                    Tense::FuturePerfect => {
1252                        todo!("IMPLEMENT FUTURE PERFECT")
1253                    }
1254                },
1255                _ => todo!("IMPLEMENT PASSIVE VOICE"),
1256            },
1257            _ => todo!("IMPLEMENT OTHER MOODS"),
1258        }
1259    }
1260
1261    pub fn last_n_chars(word: &str, n: usize) -> String {
1262        let split_pos = word.char_indices().nth_back(n - 1).unwrap_or((0, 'a')).0;
1263        word[split_pos..].into()
1264    }
1265}
1266
1267/*
1268
1269fn main() {
1270    //println!("Hello, world!");
1271
1272    let boop = Latin::last_n_chars("be", 3);
1273    //println!("boopik : {:#?}", boop);
1274    let conji = Latin::new();
1275
1276    let testik = conji.noun_map.clone();
1277    let testik2 = conji.adj_map.clone();
1278    let testik3 = conji.verb_map.clone();
1279
1280    for wot in testik {
1281        //println!("new_noun : {:#?}", wot);
1282        let new_noun = conji.noun(&wot.0, &Case::Acc, &Number::Singular);
1283        //println!("new_noun : {:#?}", new_noun);
1284    }
1285    for wot in testik2 {
1286        //println!("adj : {:#?}", wot);
1287        let new_noun = conji.adjective(&wot.0, &Case::Acc, &Number::Singular, &Gender::Feminine);
1288        //println!("adj : {:#?}", new_noun);
1289    }
1290    for wot in testik3 {
1291        //println!("verb : {:#?}", wot);
1292        let new_noun = conji.verb(&wot.0, &Mood::Indicative, &Voice::Active, &Tense::Perfect, &Number::Plural, &Person::Second);
1293        //println!("verb : {:#?}", new_noun);
1294    }
1295}
1296
1297
1298*/