1use std::borrow::Cow;
4use std::fmt;
5use std::num::NonZeroU16;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub enum Length {
14 Cells(u16),
16 Fill(NonZeroU16),
18}
19
20impl Length {
21 pub const fn fill(weight: u16) -> Self {
30 match Self::try_fill(weight) {
31 Ok(length) => length,
32 Err(_) => panic!("fill weight must be greater than zero"),
33 }
34 }
35
36 pub const fn try_fill(weight: u16) -> Result<Self, InvalidFillWeight> {
38 match NonZeroU16::new(weight) {
39 Some(weight) => Ok(Self::Fill(weight)),
40 None => Err(InvalidFillWeight),
41 }
42 }
43}
44
45#[derive(Debug, Clone, Copy, PartialEq, Eq)]
47pub struct InvalidFillWeight;
48
49impl fmt::Display for InvalidFillWeight {
50 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
51 formatter.write_str("fill weight must be greater than zero")
52 }
53}
54
55impl std::error::Error for InvalidFillWeight {}
56
57impl From<u16> for Length {
58 fn from(value: u16) -> Self {
59 Self::Cells(value)
60 }
61}
62
63#[cfg(test)]
64mod length_tests {
65 use super::{InvalidFillWeight, Length};
66
67 #[test]
68 fn fill_and_try_fill_construct_the_same_positive_weight() {
69 assert_eq!(Length::fill(1), Length::try_fill(1).unwrap());
70 assert_eq!(Length::fill(2), Length::try_fill(2).unwrap());
71 }
72
73 #[test]
74 fn try_fill_rejects_zero() {
75 assert_eq!(Length::try_fill(0), Err(InvalidFillWeight));
76 }
77
78 #[test]
79 #[should_panic(expected = "fill weight must be greater than zero")]
80 fn fill_panics_on_zero() {
81 Length::fill(0);
82 }
83}
84
85#[derive(Debug, Clone, Default, PartialEq, Eq)]
105pub enum Overflow {
106 #[default]
108 Wrap,
109 Clip(Cow<'static, str>),
112}
113
114impl Overflow {
115 pub const fn clip() -> Self {
117 Self::Clip(Cow::Borrowed(""))
118 }
119
120 pub const fn ellipsis() -> Self {
122 Self::Clip(Cow::Borrowed("…"))
123 }
124
125 pub fn clip_with(marker: impl Into<Cow<'static, str>>) -> Self {
131 Self::Clip(marker.into())
132 }
133
134 pub fn clip_marker(&self) -> Option<&str> {
136 match self {
137 Self::Wrap => None,
138 Self::Clip(marker) => Some(marker),
139 }
140 }
141}
142
143#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
145pub enum Align {
146 #[default]
147 Left,
148 Center,
149 Right,
150}
151
152#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
155pub enum VerticalAlign {
156 #[default]
157 Top,
158 Center,
159 Bottom,
160}
161
162#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
164pub struct Sides {
165 pub top: u16,
166 pub right: u16,
167 pub bottom: u16,
168 pub left: u16,
169}
170
171impl From<u16> for Sides {
172 fn from(value: u16) -> Self {
173 Self {
174 top: value,
175 right: value,
176 bottom: value,
177 left: value,
178 }
179 }
180}
181
182impl From<(u16, u16)> for Sides {
183 fn from((vertical, horizontal): (u16, u16)) -> Self {
184 Self {
185 top: vertical,
186 right: horizontal,
187 bottom: vertical,
188 left: horizontal,
189 }
190 }
191}
192
193impl From<(u16, u16, u16, u16)> for Sides {
194 fn from((top, right, bottom, left): (u16, u16, u16, u16)) -> Self {
195 Self {
196 top,
197 right,
198 bottom,
199 left,
200 }
201 }
202}