Skip to main content

ustyle/
lib.rs

1//! # μStyle || Micro Style
2//!
3//! **A text-styling library for Rust `no_std` embedded targets.**
4//!
5//! See the `README.md` for more information.
6
7#![no_std]
8#![warn(missing_docs)]
9#![deny(unsafe_code)]
10
11#[cfg(feature = "alloc")]
12extern crate alloc;
13
14/// Decoding functionality for decoding μStyle strings.
15pub mod decode;
16
17/// Encoding functionality for encoding μStyle strings.
18pub mod encode;
19
20/// Tests for μStyle.
21#[cfg(test)]
22pub mod tests;
23
24use bitflags::bitflags;
25
26/// Start character for a μStyle string.
27pub const START: char = '\x01';
28
29/// End character for a μStyle string.
30pub const END: char = '\x02';
31
32/// The length of a style written into bytes.
33///
34/// Example: `S123Hello WorldE` => 5 style bytes where S is `\x01` and E is `\x02`.
35pub const STYLE_LEN: usize = 5;
36
37/// The length of the encoded start tag string.
38///
39/// Example: `123` => 3 bytes.
40pub const DESCRIPTOR_LEN: usize = 3;
41
42/// A span of text coupled with the texts style.
43///
44/// Only available with the `alloc` feature.
45#[cfg(feature = "alloc")]
46#[derive(Clone, Eq, PartialEq, Debug, Default)]
47pub struct Span {
48    /// The text inside the span.
49    pub text: alloc::string::String,
50    /// The style of the span.
51    pub style: Style,
52}
53
54#[cfg(feature = "alloc")]
55impl Span {
56    /// Create a new span with the given text and style.
57    pub const fn new(text: alloc::string::String, style: Style) -> Self {
58        Self { text, style }
59    }
60
61    /// Sets the text of the span and returns itself.
62    pub fn with_text(mut self, text: alloc::string::String) -> Self {
63        self.text = text;
64        self
65    }
66
67    /// Sets the style of the span and returns itself.
68    pub const fn with_style(mut self, style: Style) -> Self {
69        self.style = style;
70        self
71    }
72}
73
74/// The style of a μStyle string.
75#[derive(Copy, Clone, Default, Eq, PartialEq, Debug)]
76pub struct Style {
77    /// The foreground color of the text.
78    pub foreground: Color,
79    /// The background color of the text.
80    pub background: Color,
81    /// The text attributes. See [Attributes] for more.
82    pub attributes: Attributes,
83}
84
85impl Style {
86    /// Creates a new style.
87    pub const fn new(foreground: Color, background: Color, attributes: Attributes) -> Self {
88        Self {
89            foreground,
90            background,
91            attributes,
92        }
93    }
94
95    /// Sets the foreground color of the style and returns itself.
96    pub const fn with_foreground(mut self, foreground: Color) -> Self {
97        self.foreground = foreground;
98        self
99    }
100
101    /// Sets the background color of the style and returns itself.
102    pub const fn with_background(mut self, background: Color) -> Self {
103        self.background = background;
104        self
105    }
106
107    /// Sets the attributes of the style and returns itself.
108    pub const fn with_attribute(mut self, attributes: Attributes) -> Self {
109        self.attributes = attributes;
110        self
111    }
112}
113
114/// Colors of μStyle, each assigned a unique byte.
115///
116/// There is a `None` byte to represent no color (use default color).
117///
118/// There are 7 base colors:
119/// - Gray
120/// - Red
121/// - Green
122/// - Yellow
123/// - Blue
124/// - Purple
125/// - Cyan
126///
127/// Each base color is divided into 5 variants:
128/// - Brighter
129/// - Bright
130/// - Normal
131/// - Dark
132/// - Darker.
133///
134/// Notice that gray replaces black and white, meaning darker gray equals black and brighter gray equals white.
135#[repr(u8)]
136#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Default)]
137pub enum Color {
138    /// None - implementations should use the default color
139    #[default]
140    None = 0,
141    /// Gray - rgb(128,128,128)
142    Gray = 1,
143    /// Bright Gray - rgb(192,192,192)
144    BrightGray = 2,
145    /// Brighter Gray - rgb(255,255,255)
146    BrighterGray = 3,
147    /// Dark Gray - rgb(64,64,64)
148    DarkGray = 4,
149    /// Darker Gray - rgb(0,0,0)
150    DarkerGray = 5,
151    /// Red - rgb(255,0,0)
152    Red = 6,
153    /// Bright Red - rgb(255,64,64)
154    BrightRed = 7,
155    /// Brighter Red - rgb(255,128,128)
156    BrighterRed = 8,
157    /// Dark Red - rgb(128,0,0)
158    DarkRed = 9,
159    /// Darker Red - rgb(64,0,0)
160    DarkerRed = 10,
161    /// Green - rgb(0,255,0)
162    Green = 11,
163    /// Bright Green - rgb(64,255,64)
164    BrightGreen = 12,
165    /// Brighter Green - rgb(128,255,128)
166    BrighterGreen = 13,
167    /// Dark Green - rgb(0,128,0)
168    DarkGreen = 14,
169    /// Darker Green - rgb(0,64,0)
170    DarkerGreen = 15,
171    /// Yellow - rgb(255,255,0)
172    Yellow = 16,
173    /// Bright Yellow - rgb(255,255,64)
174    BrightYellow = 17,
175    /// Brighter Yellow - rgb(255,255,128)
176    BrighterYellow = 18,
177    /// Dark Yellow - rgb(128,128,0)
178    DarkYellow = 19,
179    /// Darker Yellow - rgb(64,64,0)
180    DarkerYellow = 20,
181    /// Blue - rgb(0,0,255)
182    Blue = 21,
183    /// Bright Blue - rgb(64,64,255)
184    BrightBlue = 22,
185    /// Brighter Blue - rgb(128,128,255)
186    BrighterBlue = 23,
187    /// Dark Blue - rgb(0,0,128)
188    DarkBlue = 24,
189    /// Darker Blue - rgb(0,0,64)
190    DarkerBlue = 25,
191    /// Purple - rgb(128,0,128)
192    Purple = 26,
193    /// Bright Purple - rgb(192,64,192)
194    BrightPurple = 27,
195    /// Brighter Purple - rgb(224,128,224)
196    BrighterPurple = 28,
197    /// Dark Purple - rgb(64,0,64)
198    DarkPurple = 29,
199    /// Darker Purple - rgb(32,0,32)
200    DarkerPurple = 30,
201    /// Cyan - rgb(0,255,255)
202    Cyan = 31,
203    /// Bright Cyan - rgb(64,255,255)
204    BrightCyan = 32,
205    /// Brighter Cyan - rgb(128,255,255)
206    BrighterCyan = 33,
207    /// Dark Cyan - rgb(0,128,128)
208    DarkCyan = 34,
209    /// Darker Cyan - rgb(0,64,64)
210    DarkerCyan = 35,
211}
212
213impl Color {
214    /// Parse the given byte to a color.
215    ///
216    /// Returns [None] if the byte is invalid or represents `None`.
217    pub const fn parse(byte: u8) -> Option<Self> {
218        match byte {
219            0 => Some(Color::None),
220            1 => Some(Color::Gray),
221            2 => Some(Color::BrightGray),
222            3 => Some(Color::BrighterGray),
223            4 => Some(Color::DarkGray),
224            5 => Some(Color::DarkerGray),
225            6 => Some(Color::Red),
226            7 => Some(Color::BrightRed),
227            8 => Some(Color::BrighterRed),
228            9 => Some(Color::DarkRed),
229            10 => Some(Color::DarkerRed),
230            11 => Some(Color::Green),
231            12 => Some(Color::BrightGreen),
232            13 => Some(Color::BrighterGreen),
233            14 => Some(Color::DarkGreen),
234            15 => Some(Color::DarkerGreen),
235            16 => Some(Color::Yellow),
236            17 => Some(Color::BrightYellow),
237            18 => Some(Color::BrighterYellow),
238            19 => Some(Color::DarkYellow),
239            20 => Some(Color::DarkerYellow),
240            21 => Some(Color::Blue),
241            22 => Some(Color::BrightBlue),
242            23 => Some(Color::BrighterBlue),
243            24 => Some(Color::DarkBlue),
244            25 => Some(Color::DarkerBlue),
245            26 => Some(Color::Purple),
246            27 => Some(Color::BrightPurple),
247            28 => Some(Color::BrighterPurple),
248            29 => Some(Color::DarkPurple),
249            30 => Some(Color::DarkerPurple),
250            31 => Some(Color::Cyan),
251            32 => Some(Color::BrightCyan),
252            33 => Some(Color::BrighterCyan),
253            34 => Some(Color::DarkCyan),
254            35 => Some(Color::DarkerCyan),
255            _ => None,
256        }
257    }
258
259    /// Convert this color to a byte.
260    pub const fn to_byte(&self) -> u8 {
261        *self as u8
262    }
263
264    /// Returns the RGB value of this color as a `(r, g, b)` tuple.
265    ///
266    /// Returns [None] if the color is [Color::None].
267    pub const fn to_rgb(&self) -> Option<(u8, u8, u8)> {
268        match self {
269            Color::None => None,
270            Color::Gray => Some((128, 128, 128)),
271            Color::BrightGray => Some((192, 192, 192)),
272            Color::BrighterGray => Some((255, 255, 255)),
273            Color::DarkGray => Some((64, 64, 64)),
274            Color::DarkerGray => Some((0, 0, 0)),
275            Color::Red => Some((255, 0, 0)),
276            Color::BrightRed => Some((255, 64, 64)),
277            Color::BrighterRed => Some((255, 128, 128)),
278            Color::DarkRed => Some((128, 0, 0)),
279            Color::DarkerRed => Some((64, 0, 0)),
280            Color::Green => Some((0, 255, 0)),
281            Color::BrightGreen => Some((64, 255, 64)),
282            Color::BrighterGreen => Some((128, 255, 128)),
283            Color::DarkGreen => Some((0, 128, 0)),
284            Color::DarkerGreen => Some((0, 64, 0)),
285            Color::Yellow => Some((255, 255, 0)),
286            Color::BrightYellow => Some((255, 255, 64)),
287            Color::BrighterYellow => Some((255, 255, 128)),
288            Color::DarkYellow => Some((128, 128, 0)),
289            Color::DarkerYellow => Some((64, 64, 0)),
290            Color::Blue => Some((0, 0, 255)),
291            Color::BrightBlue => Some((64, 64, 255)),
292            Color::BrighterBlue => Some((128, 128, 255)),
293            Color::DarkBlue => Some((0, 0, 128)),
294            Color::DarkerBlue => Some((0, 0, 64)),
295            Color::Purple => Some((128, 0, 128)),
296            Color::BrightPurple => Some((192, 64, 192)),
297            Color::BrighterPurple => Some((224, 128, 224)),
298            Color::DarkPurple => Some((64, 0, 64)),
299            Color::DarkerPurple => Some((32, 0, 32)),
300            Color::Cyan => Some((0, 255, 255)),
301            Color::BrightCyan => Some((64, 255, 255)),
302            Color::BrighterCyan => Some((128, 255, 255)),
303            Color::DarkCyan => Some((0, 128, 128)),
304            Color::DarkerCyan => Some((0, 64, 64)),
305        }
306    }
307}
308
309bitflags! {
310    /// Text attributes for μStyle, represented as a bitflag.
311    ///
312    /// There are 5 attributes:
313    /// - Bold
314    /// - Italic
315    /// - Underline
316    /// - Strikethrough
317    /// - Hidden
318    #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Default)]
319    pub struct Attributes: u8 {
320        /// Make the text bold.
321        const BOLD = 1;
322        /// Make the text italic.
323        const ITALIC = 1 << 1;
324        /// Underline the text.
325        const UNDERLINE = 1 << 2;
326        /// Strikethrough the text.
327        const STRIKETHROUGH = 1 << 3;
328        /// Hide the text.
329        const HIDDEN = 1 << 4;
330    }
331}
332
333impl Attributes {
334    /// Parses the given byte to attributes.
335    ///
336    /// Returns [None] if the byte is invalid.
337    pub const fn parse(byte: u8) -> Option<Self> {
338        Self::from_bits(byte)
339    }
340
341    /// Convert this attributes to a byte.
342    pub const fn to_byte(&self) -> u8 {
343        self.bits()
344    }
345}