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}