tnil/gloss/gloss.rs
1use super::GlossFlags;
2
3/// Allows types to be glossed.
4///
5/// Glosses should be done in the style of @ırburučpaızya, or in a style consistent with the other
6/// glossing functionality of this crate. In particular, these conventions are followed:
7///
8/// - If root meanings are known (e.g. "dog" for zv), they are enclosed in “rounded double quotes”.
9/// Otherwise, roots are represented lowercase in bold or as plain Cr forms.
10///
11/// - If affix meanings are known (e.g. "large" for x/7), they are enclosed in ‘rounded single
12/// quotes’ followed by one of `₁₂₃` indicating the affix type. If the value is not known, the
13/// syntax cs₂/7 is used, where cs is replaced by the Cs form, the subscript is replaced with the
14/// affix type, and /7 is replaced with the corresponding degree. The Cs form should be in bold if
15/// possible.
16///
17/// - Category names are abbreviated UPPERCASE when glossed without the `GlossFlags::LONG` flag and
18/// unabbreviated lowercase when glossed with the `GlossFlags::LONG` flag.
19///
20/// - Multiple categories represented within a single slot are separated by `.`. The exception is
21/// affixes, which are separated by `-` when multiple are present.
22///
23/// - Multiple categories spanning multiple slots are separated by `-`.
24///
25/// - Affixes other than plain affixes (e.g. case-stackers, case-accessors, or Ca-stackers) are
26/// shown in parentheses.
27///
28/// - Multiple referents in a single slot are separated with `+` and surrounded by `[...]`.
29pub trait Gloss {
30 /// Glosses this value with a set of flags, returning the gloss as an allocated [`String`].
31 ///
32 /// Prefer using [`GlossStatic::gloss_static`] over [`Gloss::gloss`] when possible, as it avoids
33 /// allocating new memory. However, this method is often required when glossing complex types.
34 fn gloss(&self, flags: GlossFlags) -> String;
35
36 /// Glosses this value with a set of flags, returning the gloss as an allocated [`String`]. If
37 /// `flags` does not include `GlossFlags::SHOW_DEFAULTS` and `self` is the default value of
38 /// its type, an empty string is returned.
39 ///
40 /// Prefer using [`GlossStatic::gloss_static_non_default`] over [`Gloss::gloss`] when possible,
41 /// as it avoids allocating new memory. However, this method is often required when glossing
42 /// complex types.
43 fn gloss_non_default(&self, flags: GlossFlags) -> String
44 where
45 Self: Default + PartialEq,
46 {
47 if flags.matches(GlossFlags::SHOW_DEFAULTS) || *self != Self::default() {
48 self.gloss(flags)
49 } else {
50 String::new()
51 }
52 }
53}
54
55/// Allows types to be glossed without allocating.
56pub trait GlossStatic {
57 /// Glosses this value with a set of flags, returning the gloss as a `&'static str`.
58 ///
59 /// Prefer using this method over [`Gloss::gloss`] where possible, as it avoids allocating new
60 /// memory.
61 fn gloss_static(&self, flags: GlossFlags) -> &'static str;
62
63 /// Glosses this value with a set of flags, returning the gloss as a `&'static str`. If `flags`
64 /// does not include `GlossFlags::SHOW_DEFAULTS` and `self` is the default value of
65 /// its type, an empty string is returned.
66 ///
67 /// Prefer using this method over [`Gloss::gloss_non_default`] where possible, as it avoids
68 /// allocating new memory.
69 fn gloss_static_non_default(&self, flags: GlossFlags) -> &'static str
70 where
71 Self: Default + PartialEq,
72 {
73 if flags.matches(GlossFlags::SHOW_DEFAULTS) || *self != Self::default() {
74 self.gloss_static(flags)
75 } else {
76 ""
77 }
78 }
79}
80
81impl<T: GlossStatic> Gloss for T {
82 fn gloss(&self, flags: GlossFlags) -> String {
83 self.gloss_static(flags).to_owned()
84 }
85
86 fn gloss_non_default(&self, flags: GlossFlags) -> String
87 where
88 Self: Default + PartialEq,
89 {
90 self.gloss_static_non_default(flags).to_owned()
91 }
92}