mesdoc/
utils.rs

1use std::error::Error;
2
3pub fn to_static_str(content: String) -> &'static str {
4	Box::leak(content.into_boxed_str())
5}
6
7pub fn vec_char_to_clean_str(v: &mut Vec<char>) -> &'static str {
8	to_static_str(v.drain(..).collect::<String>())
9}
10
11pub fn chars_to_int(v: &[char]) -> Result<usize, Box<dyn Error>> {
12	let index = v.iter().collect::<String>();
13	let index = index.parse::<usize>()?;
14	Ok(index)
15}
16
17/**
18 * non characters
19 * https://infra.spec.whatwg.org/#noncharacter
20*/
21pub fn is_non_character(ch: &char) -> bool {
22	matches!(
23		ch,
24		'\u{FDD0}'
25			..='\u{FDEF}'
26				| '\u{FFFE}'
27				| '\u{FFFF}'
28				| '\u{1FFFE}'
29				| '\u{1FFFF}'
30				| '\u{2FFFE}'
31				| '\u{2FFFF}'
32				| '\u{3FFFE}'
33				| '\u{3FFFF}'
34				| '\u{4FFFE}'
35				| '\u{4FFFF}'
36				| '\u{5FFFE}'
37				| '\u{5FFFF}'
38				| '\u{6FFFE}'
39				| '\u{6FFFF}'
40				| '\u{7FFFE}'
41				| '\u{7FFFF}'
42				| '\u{8FFFE}'
43				| '\u{8FFFF}'
44				| '\u{9FFFE}'
45				| '\u{9FFFF}'
46				| '\u{AFFFE}'
47				| '\u{AFFFF}'
48				| '\u{BFFFE}'
49				| '\u{BFFFF}'
50				| '\u{CFFFE}'
51				| '\u{CFFFF}'
52				| '\u{DFFFE}'
53				| '\u{DFFFF}'
54				| '\u{EFFFE}'
55				| '\u{EFFFF}'
56				| '\u{FFFFE}'
57				| '\u{FFFFF}'
58				| '\u{10FFFE}'
59				| '\u{10FFFF}'
60	)
61}
62
63/**
64 *
65 * https://www.w3.org/TR/2012/WD-html-markup-20120329/syntax.html#syntax-attributes
66 * https://html.spec.whatwg.org/multipage/syntax.html#attributes-2
67*/
68pub fn is_char_available_in_key(ch: &char) -> bool {
69	if ch.is_ascii_alphanumeric() || ['_', '-', '.', ':'].contains(ch) {
70		return true;
71	}
72	if ch.is_ascii_whitespace()
73		|| ch.is_ascii_control()
74		|| is_non_character(ch)
75		|| ch.is_ascii_punctuation()
76		|| *ch == '\u{0000}'
77	{
78		return false;
79	}
80	true
81}
82pub enum RoundType {
83	Floor,
84	Ceil,
85	Round,
86}
87pub fn divide_isize(a: isize, b: isize, round: RoundType) -> isize {
88	// the rust divide method's behavior is same as 'rem'
89	// the value is near 'zero'
90	// so get the expression '(a/b) * b + (a % b) = a'
91	//
92	let mut res = a / b;
93	let remainder = a % b;
94	use RoundType::*;
95	match round {
96		Floor => {
97			// -∞ -> 0
98			if res < 0 && remainder != 0 {
99				res -= 1;
100			}
101		}
102		Ceil => {
103			// 0 -> ∞
104			if res > 0 && remainder != 0 {
105				res += 1;
106			}
107		}
108		Round => {
109			if res != 0 && remainder != 0 {
110				let symbol = if res < 0 { -1 } else { 1 };
111				let total = remainder * 2 - symbol * b;
112				// the result's symbol is same as dividend 'a'
113				if (total >= 0 && a > 0) || (total <= 0 && a < 0) {
114					res += symbol;
115				}
116			}
117		}
118	}
119	res
120}
121
122pub fn retain_by_index<T>(v: &mut Vec<T>, indexs: &[usize]) {
123	if indexs.len() < 30 {
124		for (i, index) in indexs.iter().enumerate() {
125			v.remove(index - i);
126		}
127	} else {
128		let mut loop_index: usize = 0;
129		v.retain(|_| {
130			let removed = indexs.contains(&loop_index);
131			loop_index += 1;
132			!removed
133		});
134	}
135}
136
137pub fn get_class_list(v: &str) -> Vec<&str> {
138	let v = v.trim();
139	if v.is_empty() {
140		vec![]
141	} else {
142		v.split_ascii_whitespace().collect::<Vec<&str>>()
143	}
144}
145
146#[cfg(test)]
147mod test {
148	use super::{divide_isize, RoundType};
149	#[test]
150	fn test_divide_isize() {
151		// round
152		// both positive
153		assert_eq!(divide_isize(7, 4, RoundType::Round), 2);
154		assert_eq!(divide_isize(6, 4, RoundType::Round), 2);
155		assert_eq!(divide_isize(5, 4, RoundType::Round), 1);
156		assert_eq!(divide_isize(4, 4, RoundType::Round), 1);
157		// both negative
158		assert_eq!(divide_isize(-7, -4, RoundType::Round), 2);
159		assert_eq!(divide_isize(-6, -4, RoundType::Round), 2);
160		assert_eq!(divide_isize(-5, -4, RoundType::Round), 1);
161		assert_eq!(divide_isize(-4, -4, RoundType::Round), 1);
162		// one positive, one negative
163		assert_eq!(divide_isize(7, -4, RoundType::Round), -2);
164		assert_eq!(divide_isize(6, -4, RoundType::Round), -2);
165		assert_eq!(divide_isize(5, -4, RoundType::Round), -1);
166		assert_eq!(divide_isize(4, -4, RoundType::Round), -1);
167		// one positive, one negative
168		assert_eq!(divide_isize(-7, 4, RoundType::Round), -2);
169		assert_eq!(divide_isize(-6, 4, RoundType::Round), -2);
170		assert_eq!(divide_isize(-5, 4, RoundType::Round), -1);
171		assert_eq!(divide_isize(-4, 4, RoundType::Round), -1);
172		// floor
173		// 1
174		assert_eq!(divide_isize(7, 4, RoundType::Floor), 1);
175		assert_eq!(divide_isize(6, 4, RoundType::Floor), 1);
176		assert_eq!(divide_isize(5, 4, RoundType::Floor), 1);
177		assert_eq!(divide_isize(4, 4, RoundType::Floor), 1);
178		// 2
179		assert_eq!(divide_isize(-7, -4, RoundType::Floor), 1);
180		assert_eq!(divide_isize(-6, -4, RoundType::Floor), 1);
181		assert_eq!(divide_isize(-5, -4, RoundType::Floor), 1);
182		assert_eq!(divide_isize(-4, -4, RoundType::Floor), 1);
183		// 3
184		assert_eq!(divide_isize(7, -4, RoundType::Floor), -2);
185		assert_eq!(divide_isize(6, -4, RoundType::Floor), -2);
186		assert_eq!(divide_isize(5, -4, RoundType::Floor), -2);
187		assert_eq!(divide_isize(4, -4, RoundType::Floor), -1);
188		// 4
189		assert_eq!(divide_isize(-7, 4, RoundType::Floor), -2);
190		assert_eq!(divide_isize(-6, 4, RoundType::Floor), -2);
191		assert_eq!(divide_isize(-5, 4, RoundType::Floor), -2);
192		assert_eq!(divide_isize(-4, 4, RoundType::Floor), -1);
193		// ceil
194		// 1
195		assert_eq!(divide_isize(7, 4, RoundType::Ceil), 2);
196		assert_eq!(divide_isize(6, 4, RoundType::Ceil), 2);
197		assert_eq!(divide_isize(5, 4, RoundType::Ceil), 2);
198		assert_eq!(divide_isize(4, 4, RoundType::Ceil), 1);
199		// 2
200		assert_eq!(divide_isize(-7, -4, RoundType::Ceil), 2);
201		assert_eq!(divide_isize(-6, -4, RoundType::Ceil), 2);
202		assert_eq!(divide_isize(-5, -4, RoundType::Ceil), 2);
203		assert_eq!(divide_isize(-4, -4, RoundType::Ceil), 1);
204		// 3
205		assert_eq!(divide_isize(7, -4, RoundType::Ceil), -1);
206		assert_eq!(divide_isize(6, -4, RoundType::Ceil), -1);
207		assert_eq!(divide_isize(5, -4, RoundType::Ceil), -1);
208		assert_eq!(divide_isize(4, -4, RoundType::Ceil), -1);
209		// 4
210		assert_eq!(divide_isize(-7, 4, RoundType::Ceil), -1);
211		assert_eq!(divide_isize(-6, 4, RoundType::Ceil), -1);
212		assert_eq!(divide_isize(-5, 4, RoundType::Ceil), -1);
213		assert_eq!(divide_isize(-4, 4, RoundType::Ceil), -1);
214	}
215}