1
//! CSS `text-justify` property.
2
//!
3
//! Defines [`LayoutTextJustify`] and its parser [`parse_layout_text_justify`],
4
//! used by the CSS property parsing pipeline.
5

            
6
use alloc::string::{String, ToString};
7
use core::fmt;
8
use crate::corety::AzString;
9

            
10
use crate::{format_rust_code::FormatAsRustCode, props::formatter::PrintAsCssValue};
11

            
12
/// CSS `text-justify` property value.
13
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
14
#[repr(C)]
15
#[derive(Default)]
16
pub enum LayoutTextJustify {
17
    #[default]
18
    Auto,
19
    None,
20
    InterWord,
21
    InterCharacter,
22
    /// Legacy value; the parser maps `"distribute"` to `InterCharacter` per spec.
23
    /// Retained for `#[repr(C)]` FFI backward compatibility.
24
    Distribute,
25
}
26

            
27

            
28
impl PrintAsCssValue for LayoutTextJustify {
29
    fn print_as_css_value(&self) -> String {
30
        match self {
31
            LayoutTextJustify::Auto => "auto",
32
            LayoutTextJustify::None => "none",
33
            LayoutTextJustify::InterWord => "inter-word",
34
            LayoutTextJustify::InterCharacter => "inter-character",
35
            LayoutTextJustify::Distribute => "distribute",
36
        }
37
        .to_string()
38
    }
39
}
40

            
41
impl FormatAsRustCode for LayoutTextJustify {
42
    fn format_as_rust_code(&self, _tabs: usize) -> String {
43
        format!("LayoutTextJustify::{self:?}")
44
    }
45
}
46

            
47
#[derive(Debug, Clone, PartialEq)]
48
pub enum TextJustifyParseError<'a> {
49
    InvalidValue(&'a str),
50
}
51

            
52
impl<'a> fmt::Display for TextJustifyParseError<'a> {
53
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54
        match self {
55
            TextJustifyParseError::InvalidValue(s) => {
56
                write!(f, "Invalid text-justify value: '{}'.", s)
57
            }
58
        }
59
    }
60
}
61

            
62
#[derive(Debug, Clone, PartialEq)]
63
#[repr(C, u8)]
64
pub enum TextJustifyParseErrorOwned {
65
    InvalidValue(AzString),
66
}
67

            
68
impl<'a> TextJustifyParseError<'a> {
69
    pub fn to_owned(&self) -> TextJustifyParseErrorOwned {
70
        match self {
71
            TextJustifyParseError::InvalidValue(s) => {
72
                TextJustifyParseErrorOwned::InvalidValue((*s).to_string().into())
73
            }
74
        }
75
    }
76
}
77

            
78
impl TextJustifyParseErrorOwned {
79
    pub fn to_borrowed(&self) -> TextJustifyParseError<'_> {
80
        match self {
81
            TextJustifyParseErrorOwned::InvalidValue(s) => {
82
                TextJustifyParseError::InvalidValue(s.as_str())
83
            }
84
        }
85
    }
86
}
87

            
88
/// Parses a `text-justify` CSS value string into a [`LayoutTextJustify`].
89
6
pub fn parse_layout_text_justify<'a>(
90
6
    input: &'a str,
91
6
) -> Result<LayoutTextJustify, TextJustifyParseError<'a>> {
92
6
    match input.trim() {
93
6
        "auto" => Ok(LayoutTextJustify::Auto),
94
5
        "none" => Ok(LayoutTextJustify::None),
95
4
        "inter-word" => Ok(LayoutTextJustify::InterWord),
96
3
        "inter-character" => Ok(LayoutTextJustify::InterCharacter),
97
        // +spec:text-alignment-spacing:4a88c2 - distribute computes to inter-character (legacy value alias)
98
        // +spec:text-alignment-spacing:58c33f - distribute computes to inter-character per spec clarification
99
2
        "distribute" => Ok(LayoutTextJustify::InterCharacter),
100
1
        other => Err(TextJustifyParseError::InvalidValue(other)),
101
    }
102
6
}
103

            
104
#[cfg(test)]
105
mod tests {
106
    use super::*;
107
    #[test]
108
1
    fn test_parse_layout_text_justify() {
109
1
        assert_eq!(
110
1
            parse_layout_text_justify("auto"),
111
            Ok(LayoutTextJustify::Auto)
112
        );
113
1
        assert_eq!(
114
1
            parse_layout_text_justify("none"),
115
            Ok(LayoutTextJustify::None)
116
        );
117
1
        assert_eq!(
118
1
            parse_layout_text_justify("inter-word"),
119
            Ok(LayoutTextJustify::InterWord)
120
        );
121
1
        assert_eq!(
122
1
            parse_layout_text_justify("inter-character"),
123
            Ok(LayoutTextJustify::InterCharacter)
124
        );
125
1
        assert_eq!(
126
1
            parse_layout_text_justify("distribute"),
127
            Ok(LayoutTextJustify::InterCharacter)
128
        );
129
1
        assert!(parse_layout_text_justify("invalid").is_err());
130
1
    }
131
}