anydoc 0.1.3

Convert documents (doc, docx, odt, rtf, epub, pdf, presentations, spreadsheets, csv) to GitHub-Flavored Markdown
Documentation
//! Tri-state style deltas used during cascade resolution. A property is
//! either explicitly on, explicitly off, or unset (inherit); only after the
//! full cascade is a delta collapsed into the model's resolved [`Style`].

use crate::model::Style;

#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct StyleDelta {
    pub bold: Option<bool>,
    pub italic: Option<bool>,
    pub strike: Option<bool>,
    pub code: Option<bool>,
}

impl StyleDelta {
    /// Overlay `child` on `self`: an explicit child value (on **or** off)
    /// wins; unset inherits.
    pub fn merge(self, child: StyleDelta) -> StyleDelta {
        StyleDelta {
            bold: child.bold.or(self.bold),
            italic: child.italic.or(self.italic),
            strike: child.strike.or(self.strike),
            code: child.code.or(self.code),
        }
    }

    pub fn apply(self, base: Style) -> Style {
        Style {
            bold: self.bold.unwrap_or(base.bold),
            italic: self.italic.unwrap_or(base.italic),
            strike: self.strike.unwrap_or(base.strike),
            code: self.code.unwrap_or(base.code),
        }
    }

    pub fn resolve(self) -> Style {
        self.apply(Style::PLAIN)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn explicit_off_beats_inherited_on() {
        let base = StyleDelta { bold: Some(true), ..Default::default() };
        let child = StyleDelta { bold: Some(false), ..Default::default() };
        assert_eq!(base.merge(child).resolve(), Style::PLAIN);
    }

    #[test]
    fn unset_inherits() {
        let base = StyleDelta { bold: Some(true), italic: Some(true), ..Default::default() };
        let child = StyleDelta { italic: Some(false), ..Default::default() };
        let resolved = base.merge(child).resolve();
        assert!(resolved.bold && !resolved.italic);
    }
}