rumdl_lib/types/
line_length.rs1use serde::{Deserialize, Deserializer, Serialize, Serializer};
2use std::fmt;
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, schemars::JsonSchema)]
12#[schemars(transparent)]
13pub struct LineLength(Option<usize>);
14
15impl LineLength {
16 pub fn new(value: usize) -> Self {
18 if value == 0 { Self(None) } else { Self(Some(value)) }
19 }
20
21 pub fn get(self) -> usize {
23 self.0.unwrap_or(0)
24 }
25
26 pub fn is_unlimited(self) -> bool {
28 self.0.is_none()
29 }
30
31 pub fn effective_limit(self) -> usize {
34 self.0.unwrap_or(usize::MAX)
35 }
36
37 pub const fn from_const(value: usize) -> Self {
42 if value == 0 { Self(None) } else { Self(Some(value)) }
43 }
44}
45
46impl<'de> Deserialize<'de> for LineLength {
49 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
50 where
51 D: Deserializer<'de>,
52 {
53 let value = usize::deserialize(deserializer)?;
54 Ok(LineLength::new(value))
55 }
56}
57
58impl Serialize for LineLength {
59 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
60 where
61 S: Serializer,
62 {
63 self.get().serialize(serializer)
64 }
65}
66
67impl From<LineLength> for usize {
68 fn from(val: LineLength) -> Self {
69 val.get()
70 }
71}
72
73impl fmt::Display for LineLength {
74 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75 if self.is_unlimited() {
76 write!(f, "unlimited")
77 } else {
78 write!(f, "{}", self.get())
79 }
80 }
81}
82
83impl Default for LineLength {
84 fn default() -> Self {
85 Self::from_const(80) }
87}
88
89#[cfg(test)]
90mod tests {
91 use super::*;
92
93 #[test]
94 fn test_valid_values() {
95 let unlimited = LineLength::new(0);
97 assert_eq!(unlimited.get(), 0);
98 assert!(unlimited.is_unlimited());
99 assert_eq!(unlimited.effective_limit(), usize::MAX);
100 assert_eq!(usize::from(unlimited), 0);
101
102 for value in [1, 2, 80, 100, 120, 1000] {
104 let limited = LineLength::new(value);
105 assert_eq!(limited.get(), value);
106 assert!(!limited.is_unlimited());
107 assert_eq!(limited.effective_limit(), value);
108 assert_eq!(usize::from(limited), value);
109 }
110 }
111
112 #[test]
113 fn test_from_const() {
114 const UNLIMITED: LineLength = LineLength::from_const(0);
115 assert_eq!(UNLIMITED.get(), 0);
116 assert!(UNLIMITED.is_unlimited());
117
118 const LIMITED: LineLength = LineLength::from_const(80);
119 assert_eq!(LIMITED.get(), 80);
120 assert!(!LIMITED.is_unlimited());
121 }
122
123 #[test]
124 fn test_display() {
125 let unlimited = LineLength::new(0);
126 assert_eq!(format!("{unlimited}"), "unlimited");
127
128 let limited = LineLength::new(80);
129 assert_eq!(format!("{limited}"), "80");
130 }
131
132 #[test]
133 fn test_roundtrip() {
134 #[derive(serde::Serialize, serde::Deserialize)]
135 struct TestConfig {
136 value: LineLength,
137 }
138
139 let config = TestConfig {
141 value: LineLength::new(0),
142 };
143 let serialized = toml::to_string(&config).unwrap();
144 assert_eq!(serialized.trim(), "value = 0");
145 let deserialized: TestConfig = toml::from_str(&serialized).unwrap();
146 assert_eq!(deserialized.value.get(), 0);
147 assert!(deserialized.value.is_unlimited());
148
149 let config = TestConfig {
151 value: LineLength::new(100),
152 };
153 let serialized = toml::to_string(&config).unwrap();
154 assert_eq!(serialized.trim(), "value = 100");
155 let deserialized: TestConfig = toml::from_str(&serialized).unwrap();
156 assert_eq!(deserialized.value.get(), 100);
157 assert!(!deserialized.value.is_unlimited());
158 }
159
160 #[test]
161 fn test_deserialization() {
162 #[derive(Debug, serde::Deserialize)]
163 struct TestConfig {
164 value: LineLength,
165 }
166
167 let toml_str = "value = 0";
169 let config: TestConfig = toml::from_str(toml_str).unwrap();
170 assert_eq!(config.value.get(), 0);
171 assert!(config.value.is_unlimited());
172
173 let toml_str = "value = 120";
175 let config: TestConfig = toml::from_str(toml_str).unwrap();
176 assert_eq!(config.value.get(), 120);
177 assert!(!config.value.is_unlimited());
178 }
179}