cubob/
struct.rs

1use crate::{Alternate, DisplayPair};
2use core::{
3    fmt::{DebugSet, Display, Formatter, Result as FmtResult},
4    format_args,
5};
6
7type StructEntrier = fn(&mut DebugSet<'_, '_>, &dyn Display, &dyn Display);
8
9fn usual_struct_entrier(w: &mut DebugSet, k: &dyn Display, v: &dyn Display) {
10    w.entry(&format_args!("{}: {}", k, v));
11}
12
13fn alternative_struct_entrier(w: &mut DebugSet, k: &dyn Display, v: &dyn Display) {
14    w.entry(&format_args!("{}: {:#}", k, v));
15}
16
17fn null_struct_entrier(_: &mut DebugSet, _: &dyn Display, _: &dyn Display) {}
18
19fn inherit_entrier(inherited_value: bool) -> StructEntrier {
20    match inherited_value {
21        false => usual_struct_entrier,
22        true => alternative_struct_entrier,
23    }
24}
25
26/// Lets to output some structure regarding the propagated value of output alternativeness.
27#[cfg_attr(docsrs, doc(cfg(feature = "struct")))]
28pub struct StructShow<'a, 'b> {
29    wrapper: DebugSet<'a, 'b>,
30    entrier: StructEntrier,
31    inherited_value: bool,
32}
33
34impl<'a, 'b> StructShow<'a, 'b> {
35    fn choose_entrier(alternate: Alternate, inherited_value: bool) -> StructEntrier {
36        match alternate {
37            Alternate::OneLine => usual_struct_entrier,
38            Alternate::Pretty => alternative_struct_entrier,
39            Alternate::Inherit => inherit_entrier(inherited_value),
40        }
41    }
42
43    /// Creates one [StructShow] examplar starting its output.
44    pub fn new(formatter: &'a mut Formatter<'b>, alternate: Alternate) -> Self {
45        let inherited_value = formatter.alternate();
46        let entrier = Self::choose_entrier(alternate, inherited_value);
47        Self {
48            wrapper: formatter.debug_set(),
49            entrier,
50            inherited_value,
51        }
52    }
53
54    /// Creates one [StructShow] examplar with [Alternate::Inherit] setting and starts its output.
55    pub fn inherit(formatter: &'a mut Formatter<'b>) -> Self {
56        let inherited_value = formatter.alternate();
57        let entrier = inherit_entrier(inherited_value);
58        Self {
59            wrapper: formatter.debug_set(),
60            entrier,
61            inherited_value,
62        }
63    }
64
65    /// Adds one key-value pair to the struct output.
66    pub fn field(&mut self, key: &dyn Display, val: &dyn Display) -> &mut Self {
67        (self.entrier)(&mut self.wrapper, key, val);
68        self
69    }
70
71    /// Adds one key-value pair to the struct output.
72    pub fn field_override(
73        &mut self,
74        key: &dyn Display,
75        val: &dyn Display,
76        alternate: Alternate,
77    ) -> &mut Self {
78        // Safety: since only specified subset of predefined functions can take place in self.entrier,
79        // and null_struct_entrier is one of them, the comparison through pointer values is safe enough.
80        if null_struct_entrier as usize != self.entrier as usize {
81            let entrier = Self::choose_entrier(alternate, self.inherited_value);
82            entrier(&mut self.wrapper, key, val);
83        }
84        self
85    }
86
87    /// Adds one optional key-value pair to the struct output if its value matches Some(_).
88    pub fn field_opt<T: Display>(&mut self, key: &dyn Display, val: &Option<T>) -> &mut Self {
89        if let Some(actual_value) = val {
90            self.field(key, actual_value);
91        }
92        self
93    }
94
95    /// Adds one optional key-value pair to the struct output if its value matches Some(_).
96    pub fn field_opt_override<T: Display>(
97        &mut self,
98        key: &dyn Display,
99        val: &Option<T>,
100        alternate: Alternate,
101    ) -> &mut Self {
102        if let Some(actual_value) = val {
103            self.field_override(key, actual_value, alternate);
104        }
105        self
106    }
107
108    /// Finishes the struct output, returning the result.
109    pub fn finish(&mut self) -> FmtResult {
110        self.entrier = null_struct_entrier;
111        self.wrapper.finish()
112    }
113
114    /// Adds several key-value pair to the struct output from slice.
115    pub fn fields(&mut self, fields: &[(&dyn Display, &dyn Display)]) -> &mut Self {
116        self.fields_from_iter(fields.iter())
117    }
118
119    /// Adds several key-value pair to the struct output from iterator.
120    pub fn fields_from_iter<'c, I>(&mut self, fields: I) -> &mut Self
121    where
122        I: Iterator + 'c,
123        I::Item: DisplayPair,
124    {
125        fields.for_each(|p| (self.entrier)(&mut self.wrapper, p.left(), p.rifgt()));
126        self
127    }
128
129    /// Returns value of `alternate()` of formatter used on struct examplar creation.
130    pub fn alternate(&self) -> bool {
131        self.inherited_value
132    }
133}
134
135/// Performs the whole struct output routine from creation of [StructShow] examplar to finishing (for example see the crate-level documentation).
136/// Works with slice, always inherits alternate mode.
137#[cfg_attr(docsrs, doc(cfg(feature = "struct")))]
138pub fn display_struct(f: &mut Formatter<'_>, fields: &[(&dyn Display, &dyn Display)]) -> FmtResult {
139    StructShow::new(f, Alternate::Inherit)
140        .fields(fields)
141        .finish()
142}
143
144/// Performs the whole struct output routine from creation of [StructShow] examplar to finishing.
145/// Works with iterator, always inherits alternate mode.
146#[cfg_attr(docsrs, doc(cfg(feature = "struct")))]
147pub fn display_struct_from_iter<'c, I>(f: &mut Formatter<'_>, fields: I) -> FmtResult
148where
149    I: Iterator + 'c,
150    I::Item: DisplayPair,
151{
152    StructShow::new(f, Alternate::Inherit)
153        .fields_from_iter(fields)
154        .finish()
155}