forked from RustPython/RustPython
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathstr.rs
More file actions
124 lines (112 loc) · 3.22 KB
/
Copy pathstr.rs
File metadata and controls
124 lines (112 loc) · 3.22 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
use std::ops::{Bound, RangeBounds};
#[cfg(not(target_arch = "wasm32"))]
#[allow(non_camel_case_types)]
pub type wchar_t = libc::wchar_t;
#[cfg(target_arch = "wasm32")]
#[allow(non_camel_case_types)]
pub type wchar_t = u32;
pub fn try_get_chars(s: &str, range: impl RangeBounds<usize>) -> Option<&str> {
let mut chars = s.chars();
let start = match range.start_bound() {
Bound::Included(&i) => i,
Bound::Excluded(&i) => i + 1,
Bound::Unbounded => 0,
};
for _ in 0..start {
chars.next()?;
}
let s = chars.as_str();
let range_len = match range.end_bound() {
Bound::Included(&i) => i + 1 - start,
Bound::Excluded(&i) => i - start,
Bound::Unbounded => return Some(s),
};
char_range_end(s, range_len).map(|end| &s[..end])
}
pub fn get_chars(s: &str, range: impl RangeBounds<usize>) -> &str {
try_get_chars(s, range).unwrap()
}
#[inline]
pub fn char_range_end(s: &str, nchars: usize) -> Option<usize> {
let i = match nchars.checked_sub(1) {
Some(last_char_index) => {
let (index, c) = s.char_indices().nth(last_char_index)?;
index + c.len_utf8()
}
None => 0,
};
Some(i)
}
pub fn zfill(bytes: &[u8], width: usize) -> Vec<u8> {
if width <= bytes.len() {
bytes.to_vec()
} else {
let (sign, s) = match bytes.first() {
Some(_sign @ b'+') | Some(_sign @ b'-') => {
(unsafe { bytes.get_unchecked(..1) }, &bytes[1..])
}
_ => (&b""[..], bytes),
};
let mut filled = Vec::new();
filled.extend_from_slice(sign);
filled.extend(std::iter::repeat(b'0').take(width - bytes.len()));
filled.extend_from_slice(s);
filled
}
}
/// Convert a string to ascii compatible, escaping unicodes into escape
/// sequences.
pub fn to_ascii(value: &str) -> String {
let mut ascii = String::new();
for c in value.chars() {
if c.is_ascii() {
ascii.push(c)
} else {
let c = c as i64;
let hex = if c < 0x100 {
format!("\\x{:02x}", c)
} else if c < 0x10000 {
format!("\\u{:04x}", c)
} else {
format!("\\U{:08x}", c)
};
ascii.push_str(&hex)
}
}
ascii
}
#[doc(hidden)]
pub const fn bytes_is_ascii(x: &str) -> bool {
let x = x.as_bytes();
let mut i = 0;
while i < x.len() {
if !x[i].is_ascii() {
return false;
}
i += 1;
}
true
}
#[macro_export]
macro_rules! ascii {
($x:literal) => {{
const _: () = {
["not ascii"][!$crate::str::bytes_is_ascii($x) as usize];
};
unsafe { $crate::vendored::ascii::AsciiStr::from_ascii_unchecked($x.as_bytes()) }
}};
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_get_chars() {
let s = "0123456789";
assert_eq!(get_chars(s, 3..7), "3456");
assert_eq!(get_chars(s, 3..7), &s[3..7]);
let s = "0유니코드 문자열9";
assert_eq!(get_chars(s, 3..7), "코드 문");
let s = "0😀😃😄😁😆😅😂🤣9";
assert_eq!(get_chars(s, 3..7), "😄😁😆😅");
}
}